Skip to content

Partials

Andreas Dausenau edited this page Sep 15, 2023 · 24 revisions

Partials

Ez-on-rails shows a set of partials and some tweaks you can use to render several reusable things in the backend. For instance, the forms to update or create records that use the render info make use of the shared/model_form partial.

The following sections describe the usage of some of this partials. Please note that not all partials are described in detail, because the many of them are used automaticly by the system.

If you want to see all partials and manipulate them, you can use the ezviews generator to eject them. However this is not recommended. This will eg. eject all the partials used by the layout, however you are able to just make use of them or change their behavior. Just have a look the layout documentation page if you want to change some appearance of your application or want to implement some custom page that uses modals or something ez-on-rails provides out of the box.

Note that some of the core partials are also defined on the layout page, because some of them can also be used for custom pages but are also configurable over instance variables or settings.

This page provides the partials you can use that are not part of the layout, meaning being not visible on the whole page or can not be accessed using helpers.

Simple tables

The partial ez_on_rails/shared/table enables you to show simple tables.

It takes the two parameters table_header and table_rows:

  • table_header is an array of strings defining the headers of the table.
  • table_rows is an array of arrays of strings. The first layer of arrays describe the rows, the second one the columns of contents.

Example :

render partial: 'ez_on_rails/shared/table', 
       locals: {
         table_header: [ "Title", "Created at" ], 
         table_rows: [
           ["Article one", "2022-06-01"], 
           ["Article two", "2022-06-02"]
         ]
       }

This is a very simple way to show tables without additional functionality. They are thought to show static content. If you want to have more flexibility like eg. the possibility to select items from the table and process actions on them, have a look at enhanced tables that are described in the next section.

Enhanced tables

The partial ez_on_rails/shared/enhanced_table shows a table having additional configurable functionality, like actions that can be performed on selected table items.

Therefore each item of the table gets a checkbox as first column that makes the items selectable, including a checkbox in the header to select all table items at once.

The actions you define that are processable for the selected items are displayed as buttons beyond the table. If a user clicks one of this buttons, an action will be called and the selected items will be passed to the action.

For example, the index views that are generated using the ezscaff generator make use of the enhanced table. The button to destroy the selected items is one of this described action buttons.

The partial expects the following parameters:

  • :table_id - a string that is used to identify the table. This is optional, but if you want to use many ehanced tables on one page, you need to specify it.
  • :table_header - an array of hashes defining the header columns. Each have has the following attributes
    • :content - the column title string
    • :col_class - an optional string of additional css classes that are passed to the th element of the column
  • :table_rows - an array of hashes to describe the content rows, every hash has the following attributes
    • :id - the id of the row, needed if your table is selectable. The actions make use of this id to identify the row.
    • :cols - an array of hashes having the columns contents. The hases have the following attributes:
      • :content - The content of the cell as string
      • :col_class - an optional string of additional css classes that are passed to the td element of the cell
    • :data - a hash of key value pairs holding data that is passed to the actions.
  • :selectable - a hash holding info about the possibilities of performable actions to selected items. If this hash is given, the table is mentioned as selectable and the checkboxes will be rendered. The has has the following attributes:
    • :actions - an array of hashes holding the info about the actions that can be performed on the selected items. For every given action a button beyond the table will be rendered. Every hash has the following attributes
      • :label - the label of the action button
      • :type - the bootstrap type of the button, only used for styling (eg. primary, secondary, success, ...)
      • :target - the url that is called if the user clicks the button. If the user clicks the button, the selected items will be passed as parameters to this url. This url is interpreted using url_for, hence you can pass any rails conform url. The section [enhanced table actions](### Enhanced table actions) section shows you how you can implement the action behind the button on the rails side.
      • :method - the method used for the url
      • :onclick - can be used instead of the url, to perform a javascript action on button click. The function must get one parameter holding the selected items. It must be placed in the document ($). The selected items parameter holds an array of json objects, where each json object describes one selection. The json object holds the "id" and "data" attributes, where "id" is the previously defined id of the selected row and "data" is the json object of data that was defined in the data attributes of the row.
      • :confirm - can be a boolean, string or hash to enable a confirmation the user has to accept before the action is performed. The boolean enables the default confirm message. If you pass a string, the message will be replaced. If you pass a hash, it must have the following attributes.
        • :message - the message shown in the confirmation box

If you want to use the enhanced_table using a scaffold, you can make use of the enhanced table helpers, that are described in [this section]( ### Enhanced table helpers).

Lets have a look at an example:

render partial: 'ez_on_rails/shared/enhanced_table', 
       locals: {
         table_header: [
           { content: 'Title', col_class: 'title-header' },
           { content: 'Created at' }
         ], 
         table_rows: [
           {
             id: Article.first.id,
             cols: [
               { content: Article.first.title, col_class: 'title-cell' },
               { content: Article.first.created_at.to_s }
             ],
             data: {
               record_id: Article.first.id
             }
           },
           ...
         ],
         selectable: {
           actions: [
             {
               label: 'Approve',
               type: 'primary',
               target: approve_articles_path,
               method: 'post',
               confirm: {
                 message: 'Do you really want to approve the selected artiles?'
               }
             },
             ...
           ]
         }
       }

Enhanced table helpers

There are two helper methods given by the EzOnRails::EzScaffHelper you can use to render lists of records of models that were generated using the ezscaff generator.

  • get_table_headers takes the model class as first parameter. The render_info is passed as second parameter and builds the header row for the model list. The third parameter is a hash having additional options for the view. This hash can have the following attributes
    • print_show: true - prints a header cell of the col that holds the links to the show action of each resource
    • print_edit: true - prints a header cell of the col that holds the links to the edit action of each resource
    • print_destroy: true - prints a header cell of the col that holds the links to the destroy action of each resource
    • print_controls: true - prints the header cells for cols holding the show, edit and destroy links for each resource
  • get_table_rows takes as first parameter the collection of records that should be listed in the table. The second parameter is the render_info of the model. The third parameter is a hash having additional options for the view. The hash can have the following attributes:
    • print_show: true - prints the cell that holds the link to the show action of the resource
    • print_edit: true - prints the cell that holds the link to the edit action of the resource
    • print_destroy: true - prints the cell that holds the link to the destroy action of the resource
    • print_controls: true - prints the cells that hold the links to the show, edit and destroy actions of the resource
    • search_params: the ransack search params if you use a search form to filter the displayed items in the table. This is passed to the destroy link, hence if the user destroys a record, he will keep the filtered results after the destroy.
render partial: 'ez_on_rails/shared/enhanced_table', 
       locals: {
         table_header: get_table_headers(Article, render_info_article, { print_controls: true }),
         table_rows: get_table_rows(Article.all, render_info_article, { print_controls: true }))
       }

Enhanced table actions

The EzOnRails::EzAjaxHelper can be used to implement actions for the enhanced table. He is already included in the EzOnRails::ResourceController.

If the user selects some items in an enhanced table and executes an action for this items, there exist some helper methods giving you the necessary information about the executed action.

The method enhanced_table_selections_action takes one hash as parameter and accepts a Block. The optional first parameter hash has the following attributes:

  • redirect_target - The target path or url that is called after the action was executed. This is passed to url_for, hence you can pass any rails like value here. If the parameters of the current action has ransack compatible filters, they are passed to the target. This enables you to have filtered enhanced tables using ransack. If the action is executed, the filtered results keep visible.

The block given to the method accepts the following parameters:

  • selected_ids - is an array of row ids the user selected in the table.
  • selected_data - is a hash, having the ids as keys and the additional data given by the table as value hash.

If the redirect target is not specified, the index action of the current context will be the target.

The method will now call the given block and after that redirect to the target.

def ArticlesController < EzOnRails::ResourceController
  ...
  # POST /articles/approve
  def approve
    enhanced_table_selections_action({ redirect_target: articles_path }) do |_selected_ids, selected_data|
      selected_data.values.each do |data|
        article = Article.find_by(id: data['record_id'])
        next unless article

        article.update(approved: true)
      end
    end
  end
end

As you can see, the previously passed data is now given by the selected data. In this example we do not need the selected_ids of the rows, because we passed the record id as data field, but maybe you will need it for your action.

If you dont want to use this block method, you can also get the selections by using enhanced_table_selections(params). But we do not recommend this. This method will return the seletced elements as list. But it should only be used if you can not use the previously mentiond method.

Search form

The partial shared/search_form renders a form to search for records. The form is built from the render info of a model.

The search form is included in the index action of a scaffold that was generated using the ezscaff generator by default. But if you want to use the partial in some other location, you have to mention about some things:

  1. You need a POST and GET action that is needed by the search. This action are called on submit and rendering the search form. For example:
resources :articles do
  collection do
    match 'search' => 'some_resource#search', via: [:get, :post], as: :search
  end
end
  1. The controller action needs to execute the search. You need to call the ransack method on the model and pass the q param to filter the records by the search. For example:
...
# POST | GET search
def search
  @queue_obj = Article.ransack(params[:q])
  @obj_class = Article
  @resource_objs = @queue_obj.result
end
...

Note: The partial needs the @obj_class and @queue_obj variables.

  1. Call the search partial in the view and pass the variables given by the controller. For Example:
= render partial: 'shared/search_form', locals: {\
         queue_obj: @queue_obj,
         obj_class: @obj_class,
         render_info: render_info_article,
         print_details_tag: :true\

If you pass the print_details_tag option, the search form will be rendered in a details and summary html tag, hence it is expandable. If you pass :open instead of true here, the details tag will be opened as default.

You can as usual pass the :search_form options in the render info as described. For example:

...
  def render_info_article
    {
      name: {
        label: 'Name',
        search_method: :eq
      },
      content: {
        label: 'Content',
        hide: [:search_form]
      }
      ...
    }
  end
...

The functions that render the search fields are implemented in the search_form_helper. If you want to change them, you need to eject using the ezhelpers generator.

The methods here do not take the form object itself as data argument. The data argument is a hash having the values :obj_class und :form, where :obj_class is the class of the model to search on and :form is the form builder you can render the field with.

As you can see in the example above, you can change the default search method used for the field. Normally the default method is cont, meaining contains. You can use any type that is available via ransack.

Append content to model_form and form partials

The partials _shared/form and shared/model_form take an optional parameter :behind_submit. This parameter enables you to append content behind the formular without the need to copy the partials content.

The parameter can either be a Proc or some other renderable value.

If you pass a proc, the form builder will be given as parameter.

Add javascript to model_form

The partial _shared/model_form automatically registers a stimulus controller. That controller is expected to be within the app/javascript/controllers folder. Note that from here, the path to the stimulus controller must be the same like your normal ruby controller, including the subfolders for namespaces. The file must also be the same name like your controller in ruby.

Inside the controller, you can define onChange methods for each attribute. The model_form partial will automatically register onChange listeners to all fields you defined in the render info.

The listeners signature must start with onChange followed by the camelized name of the attribute. E.g.:

...
    onChangeArticleType(event) {  
        console.log("Change event for article_type attribute", event); 
    }
...
``

It is also possible to access the fields directly by using stimulus targets. The model_form partial defines targets for each field, named with the camelized name of the attribute followed by "Field". Inside stimulus you must define the targets in the static targets array. After that, you can access them the following way:

... static targets = ['articleTypeField'] ...

... onChangeArticleType(event) {
console.log("Id of the article_type field", this.articleTypeFieldTarget.id); } ...


A default controller having onChange listeners and targets for all attributes for a scaffold is generated by the [ez-scaff](https://github.com/D4uS1/ez-on-rails/wiki/ezscaff) generator.

You can also pass initial values to the javascript controller by passing the __stimulus_values__ hash to the partials render method.

= render partial: 'ez_on_rails/shared/model_form', locals: {
render_info: render_info_article, obj: article, stimulus_values: {
hello_message: "hello world", } }


The passed values are available in the stimulus controller, by using the __data.get__ method of the controller. Note that you must use the camelized key of your variable here.

... export default class extends Controller { ...

connect() {
   alert(this.data.get("helloMessage"));
}
...

}


## Custom links in scaffold partials
The most scaffold partials like e.g. __shared/show__ takes parameters to define custom links to other scaffold actions.
If you do not pass those parameters, they are resolved to the default rest actions.

* :index_url - url or proc
* :edit_url - url or proc
* :show_url - url or proc
* :destroy_url - url or proc
* :post_url - url or proc - you can also define :post_method in combination with this

If any button or link on the partial targets one of the parameters, it will be replaced if you define it.
If you pass a proc to the parameters, the proc will take the record as first parameter.

## Show back link
Some partials support rendering a link button to redirect to the last visited page.
Just pass __:print_back__ and the button will be rendered.
If you pass just the value _true_, the default label will be rendered.
If you pass an hash with the key __label__, the label will be printed on the back button.

## Change link labels
In some partials that render link buttons, like the most scaffold targets like e.g. __shared/show__, you are able to change the label of the buttons. Just pass hashes having the __label__ key instead of booleans to the print parameters of the proper targets.

= render partial: 'shared/index', locals: { render_info: render_info_article, resources: @resource_objs, print_show: { label: 'Wow, look at this' }, print_edit: { label: 'Naaah, need to correct first' }, print_destroy: { label: 'Puh, remove that nasty stuff' }, print_new: { label: 'Create a fancy new one' } }


There is one special case for the __shared/model_form__ partial. You can pass the options __save_label__ and __hide_save_icon__ for the submit button here. If hide_save_icon is set to true, the icon located before the save text will not be rendered.

= render partial: 'shared/model_form', locals: { render_info: render_info_article, print_index: true, save_label: 'Ready to save', hide_save_icon: true, obj: @resource_obj }