# Bootbox modal CRUD Provides Rails modal CRUD scaffolding powered by bootstrap & bootbox & simple_form. Built for use with Turbolinks, jQuery and Twitter Bootstrap 3. ## Initial setup Set custom scaffolding generators in your ```config/application.rb``` config.generators do |g| g.template_engine :haml_modal_crud g.resource_route :modal_crud_route end Require the main javascript file in your ```app/assets/javascripts/application.js``` //= require bootbox_crud_main Require the main stylesheet file in your ```app/assets/stylesheets/application.css``` and also don't forget to add the main Bootstrap stylesheet *= require bootstrap *= require bootbox_crud_main Add bootbox alert markup into the main container of your ```app/views/layouts/application.html.haml``` %body .container = yeild = bb_alert Run the install generator to copy over default simple_form initializers and models.js for defining modal CRUD enabled models $ bundle exec rails g bootbox_crud:install ## Scaffolding Custom model scaffolding is enabled by installing and configuring this gem. The generated files are following the rules described in the Modal CRUD section. $ bundle exec rails g scaffold Block name width:integer height:integer depth:integer The above code will give you a ready to use, nicely formatted modal enabled Block CRUD. Just migrate the DB. # Modal CRUD with [bootbox.js](https://github.com/rocsci/bootbox-rails) This concept is a work in progress and suggestions are welcome. Main source files are in the gem: vendor/assets/javascripts/bootbox_crud_modals.js app/views/modals/_form.js app/views/modals/_alert.js app/views/modals/_create.js app/views/modals/_destroy.js app/views/modals/_update.js and in your application app/assets/javascripts/models.js ## Controller ### Create, update and destroy All of these methods must have a js response format defined in the respond_to block. Update example: respond_to do |format| if @model.update(model_params) ... format.js else ... format.js end end end ### New, edit and show If you want your modals to be fast, related actions shouldn't render with a full layout. Instead return only the form or detail template. In another words, use ``` render layout: false ```. def new @model = Model.new respond_to do |format| format.html { render layout: false } format.json { render json: @model } end end def edit render layout: false end #### Different show view template for modal and normal page In cases where a separate view template is needed for modal and normal full page show action, you can achieve that by doing the following. The modal show request accepted content type is \*/\* so it is going to take the .js format response option as acceptable, because it is the first in the list. A standard request will skip format.js and take the html option. def show respond_to do |format| format.js { render 'show_modal', layout: false } format.html end end This method can also be used for differentiating edit and new actions for modal and normal views. ## Views ### Create, update and destroy Three new files have to be added to the views directory of the related model: **create.js.erb** <%= render partial: 'modals/create', locals: { model: @model, form_path: 'model/form' } %> **update.js.erb** <%= render partial: 'modals/update', locals: { model: @model, form_path: 'model/form' } %> **destroy.js.erb** <%= render partial: 'modals/destroy', locals: { model: @model, form_path: 'model/form' } %> The partials in app/views/modals directory should provide the necessary functionality for most cases. If you need some special behaviour, implement it instead of rendering the partial. **Create/Destroy visit_path** [optional parameter]: determines what page to load after the model has been created/destroyed. The path is visited by invoking Turbolinks.visit(visit_path). If it isn't set, the current page will be reloaded. It is mostly useful in cases: * when you create a new model and want to redirect to its full page detail or when you create a new subpage/tab and you want to refresh the page with an anchor after the base URL (the example is used for overviews) <%= render partial: 'modals/create', locals: { model: @overview, form_path: 'overviews/form', visit_path: "#overview_#{@overview.id}" } %> * where you can delete a model from its full page detail and you need to redirect the user to some list view, a simple page reload wouldn't be useful because the model was destroyed and its detail can't be shown anymore <%= render partial: 'modals/destroy', locals: { visit_path: "/#{ location_name.to_s }/unipolars" } %> ### New, edit and show All views being shown inside a modal window must have a root node with ```id='content'```. Example in haml: #content = render 'form' The javascript handling the response will fill this node and its contents into the modal window body. #### Forms Forms used inside of modal windows need to have the remote attribute set to true. = simple_form @model, remote: true This way they are submitted via an ajax request. The ```ApplicationHelper#remote_form_options``` helper with default simple\_form formatting and layout wrapping options should be used instead of only writing ```remote: true``` to keep all forms unified. But more on that in the main forms section of this readme. #### Show helpers Use these in case you want to show values of a model in a modal window. show_value(label, value) show_link_to(label, object, link_text) show_link_to_array(label, objects, name_object_field) show_value 'Name', @model.name show_link_to 'Model', @model, @model.name show_link_to_array 'Model blackboxes', @model.blackboxes, 'name' Wrap them into a div with ```class='form-horizontal'```. Bootstrap horizontal form layout with little customization is used to display the values. Adding ```class='show'``` to root node with ```id='content'``` is mandatory to get the right styling. If you forget this one, it will look like input fields. #content.show .form-horizontal = show_value 'Name', @model.name = show_value 'Status', @model.status ### Links to modals Making links modal enabled is done via data attributes. data-entity='Model' data-action='update' data-id='1' In haml: = link_to '#', :class => 'btn btn-primary btn-sm', data: { id: @model.id, entity: 'Model', action: 'update' } do %i.fa.fa-edit edit There is a global button handler searching for any DOM nodes with 'data-entity' attribute. Click events of such nodes lead to modals. The logic is simple, clicking on a node with the above values will lead to this function invocation: BBCrud.Model.update({id: 1}) Available actions are: * create * update * show #### Adding a new model to modals on the client side The above mentioned functions are defined in **models.js**, if you want to add modals to a new model, you have to add a new line there. BBCrud.Models.add(namespace, baseUrl, modalHeaderTitle); * **namespace** is used to define the BBCrud.Unipolar object * **baseUrl** is setting the base route for the models actions * **modalHeaderTitle** is used in modal titles, it should be a singular downcase name of the model Filled in for unipolars: BBCrud.Models.add('Unipolar', '/unipolars/', 'unipolar'); The above function invocation creates these functions: BBCrud.Unipolar.create BBCrud.Unipolar.update BBCrud.Unipolar.show Now you should be all set to click your data-entity links and call the functions from your scripts if needed. *Note*: I18n is currently not supported on the client, there are a few ways how to approach it. The necessary changes should be simple. #### Adding custom actions to models (non CRUD) Is done in ```models.js``` by adding a line similar to the for defining CRUD actions. Here is an example for close event action: BBCrud.Models.addAction('Event', '/events/', 'event', 'close'); The first three arguments are the same as for ```BBCrud.Models.add``` function, the last argument is the new action name. After adding this line, you can create a button with the following data attributes and your modal is almost ready. data-entity='Event' data-action='close' data-id='1' Of course you have to do all the little tweaks on this action, as you did for CRUD. Meaning, adding ```#content``` to the form view and rendering it without layout. Next adding ```format.js``` to the relevant controller action and creating a ```*.js.erb``` view template for it. To finish our ```Event.close``` example, the file will be named ```events/close_event.js.erb``` and it's contents: <%= render partial: 'modals/form', locals: { model: @event, form_path: 'events/close', success_alert: 'Closed' , error_alert: 'Error while closing' } %> The important detail to notice is the use of ```modals/form``` partial, which was made to handle custom actions. The rest of the arguments are self-explanatory. ## Modals in short * Create format.js lines in respond_to block of controller :create, :update, :destroy * Return views without layout in controller :new, :show, :edit * Make sure your views have a root ```id='content'``` node & with ```class='show'``` in case of a show view using show helpers from this guide * Make sure your form has ```remote: true``` or preferably ```remote_form_options``` with simple\_form, the layout should be the same as in the example in form section of this README * Add create, update and destroy .js.erb files to the view directory and fill them according to this guide * Add your model definition as a new line to models.js * Add ```data-entity```, ```data-action``` and ```data-id``` with the right values to an element on the page and click it, or call ``BBCrud.ModelName.create/update/show()`` from your javascript to show the modal ## Custom scaffold source files If you want have a peek or override some of the scaffolding templates, here is an overview of the files used: **haml\_modal\_crud** lib/generators/rails/haml_modal_crud/templates/create.js.erb lib/generators/rails/haml_modal_crud/templates/destroy.js.erb lib/generators/rails/haml_modal_crud/templates/update.js.erb lib/generators/rails/haml_modal_crud/haml_modal_crud_generator.rb lib/generators/rails/haml_modal_crud/USAGE **modal\_crud\_route** lib/generators/rails/modal_crud_route/modal_crud_route_generator.rb **haml scaffold templates override** lib/templates/haml/scaffold/_form.html.haml lib/templates/haml/scaffold/edit.html.haml lib/templates/haml/scaffold/index.html.haml lib/templates/haml/scaffold/new.html.haml lib/templates/haml/scaffold/show.html.haml **controller scaffold template override** lib/templates/rails/scaffold_controller/controller.rb # TODOs * I18n support on client side * Improve BBCrud.Alert / integration with Rails flash messages * Generator tests