Redactor Rails renders multiple forms - ruby-on-rails

I've successfully installed the gem 'redactor'rails' and can call it in a form, and update a note successfully.
Problem: When creating a post, the form renders multiple input areas. When I update/edit an existing post, the more times I click "Edit", more input areas are rendered. Why does it render multiple fields?
_form.html.haml
= simple_form_for #note do |f|
= f.input :title
= f.input :content, :input_html => { :class => "redactor" }
= f.button :submit, class: "button"

You should destroy old instances of Redactor for each selector before initializing it.
$('.redactor').redactor('core.destroy');

Related

Issue during validation and render

I have an issue when submitting a form.
I have two models, :service and :booking. For a service, there is a button:
<%= link_to "Book Now", new_booking_path(service_id: #service.id) %>
When this button is clicked it takes the user to the _form.html.erb where they can book the service. This is the simplified booking form:
<%= simple_form_for (#booking) do |f| %>
<%= f.label "Booking Date" %><br>
<%= f.text_field :date %>
<%= f.text_field :time, :id => "timepicker" %>
<%= f.input :address, label: "Address" %>
<%= f.input :postcode, label: "Postcode" %>
<%= f.input :suburb, label: "Suburb" %>
<%= f.input :servicetitle, :input_html => { :value => #service.title } %>
<%= f.input :serviceprice, :input_html => { :value => #service.price } %>
<%= f.input :servicetime, :input_html => { :value => #service.time } %>
<%= f.button :submit %>
<% end %>
As you can see, I have three fields, :servicetitle, :serviceprice and :servicetime.
These fields get their input values from the #service.id value passed through the link_to button. I am able to access the records like #service.title using this instance variable in the bookings_controller:
#service = Service.find_by_id(params[:service_id])
The problem I am having is that if one of the field validation fails (say the :date field), then the user gets redirected back to the _form.html.erb and I get the error
NoMethodError in Bookings#create
undefined method title
I would also get the errors:
undefined method price
and:
undefined method time
I think this is because Rails doesn't have access to the #service instance variable anymore?
How am I able to fix this when a validation fails?
Edit:
Create method in bookings controller:
def create
#booking = current_user.bookings.build(bookings_params)
if #booking.save
BookingMailer.form_confirmation(#booking).deliver
redirect_to #booking
else
render 'new'
end
end
I am pretty sure this is down to the fact that in your create method you have not assigned anything to the #service variable, in your new method you are instantiating the #service variable (at least I assume you are as you are not getting an error when you go to the 'action'), but you are not doing it in the create action.
When you go to the create action, the whole request cycle starts from scratch, meaning anything you did in the 'new' action is gone.
When you have an error, your create action goes to the else block and runs render 'new' which renders the new.html.erb template from scratch, if you are rendering a template with an #service variable, then you will need to define that variable in the action before you render the template. eg #service = Service.new or #service = Service.find(params[:service_id]). Otherwise, your template is calling the title price and time methods on a nil object.
You haven't passed the service id again to create method so probably it won't be getting the params[:service_id] in create.
Add a hidden field in form with the service_id and then check.
<%= hidden_field_tag(:service_id,#service.id) %>

Model-independent Rails 4 file upload in dynamically loaded (nested) form field

I'm looking for a way for simple image upload onto the file system so that the image is not stored in the database. I understand this step is rather easy, just using a file_input tag, however I have problems making it happen because of how my form is built.
I have a project where I create static campaign pages by having a user specify a page layout, or a template, for the page. Once the user selects which template they want to load for their page, a form is loaded that contains a section for each of the widgets that the specified template contains. The user inputs their information, presses submit, and a static page is created.
One of the widgets is an image widget, where the user should select a file from their system and that should get uploaded to the server on submitting the form. The problem is that because of how I'm using the form helpers, I'm facing the issue, where file upload gives filename as a string instead of the IO object (https://www.ruby-forum.com/topic/125637). I need help on trying to work around this.
The form for inputting data onto the page (which is stored in the table campaign_pages) looks like this:
= form_for(#campaign_page, class: 'form-horizontal') do |f|
fieldset
legend Basic page information
.form-group
= f.label :featured, class: 'control-label col-lg-2'
.col-lg-10
= f.check_box :featured, class: 'form-control'
= f.label :title, class: 'control-label col-lg-2'
.col-lg-10
= f.text_field :title, placeholder: 'Unique and really catchy page title!', class: 'form-control'
= f.label :campaign_id, 'Campaign: ', class: 'control-label col-lg-2'
.col-lg-10
= f.select :campaign_id, options_from_collection_for_select(#campaigns, 'id', 'campaign_name', #campaign), {}, html_options= {:class => 'form-control'}
= f.label :language_id, 'Language: ', class: 'control-label col-lg-2'
.col-lg-10
= f.select :language_id, options_from_collection_for_select(Language.all,'id', 'language_name'), {}, html_options= {:class => 'form-control'}
label for='template_id' class='control-label col-lg-2' Template:
.col-lg-10
= select_tag 'template_id', options_from_collection_for_select(#templates, 'id', 'template_name', #template), class: 'form-control'
| data-no-turbolink="true"
This is where forms for content for each widget on the page gets loaded once a template has been selected:
#widget_location
= render :file => 'templates/show_form', layout: false
.form-group
= f.submit 'Save Page', class: 'btn btn-sm btn-primary'
The form for the image widget (which creates the problem) looks like so:
#image_widget_form.form-group
= label_tag 'widgets[image][image_url]', 'Image URL:', class: 'control-label col-lg-2'
.col-lg-10
= text_field_tag 'widgets[image][image_url]', options['image_url'], class: 'form-control'
= hidden_field_tag 'widgets[image][widget_type]', WidgetType.find_by(:widget_name => 'image').id
= file_field_tag 'widgets[image][image_upload]'
After reading the documentation (http://guides.rubyonrails.org/form_helpers.html#uploading-files) and other issue reports, my understanding is that the problem is "multipart => true", which you have to specify if you want your file field tag to work. That shouldn't be a problem, because I'm using form_for #campaign_page instead of form_tag. However, the widgets and their content do not belong to the campaign page table, and so they aren't specified in the model for a campaign page. Thus, I can't simply use f.file_field for the file input.
I'm looking for a solution for this. Would using nested attributes and then using field_for for the image upload work?
Another issue is that specifications and content for the widgets are stored in a Postgres JSONB field, and I'm not sure how nested attributes would work for those.
I assumed that the form had multipart set, because specifying multipart => true for a form_for helper is not necessary according to Rails documentation. The fix turned out to be pretty simple, however - it works after setting multipart: true in a html options hash for the form tag:
= form_for(#campaign_page, class: 'form-horizontal', html: {multipart: true}) do |f|
...

redirect from new action to create action with params

Im trying to design a shopping cart. i.e a customer shopping online adds a product to their trolley.
I want to go straight to create action from my new action without going to new.html.erb with pre-set values in my params
Here is what I have so far:
#trolley_id += 1
redirect_to :controller => 'trolleys', :action => 'create', :id => #trolley_id, :something => 'else', method: :post
This redirects me to my index action
To do this with javascript templates, it would look like this:
view
= form_form Trolley.new, remote: true do
-# form goes here
The remote true will submit it as javascript, which will try to render a javascript template.
Your create action can either render :create or let Rails render your template automatically. Since it came in as a javascript request, Rails will render the template with format js.
trolleys/create.js.erb
var html = "<%= j render 'trolley_row', trolley: #trolley %>
$('table.trolleys body').append(html);
I managed to resolve my problem. I created a form in my Product_controller#show that will go straight to my Trolley_controller#create and create an entry in my Trolleys table
<%= simple_form_for [#product, #trolley] do |f| %>
<%= f.input :quantity, collection: 1..12, prompt: "select quantity" %>
<%= f.input :product_id, :as => :hidden %>
<%= f.input :user_id, :as => :hidden %>
<%= f.button :submit, "Add to Basket" %>
<% end %>

Rails ajax form not submitting from within another

I have a Rails 3.2 ajax form that creates a new Room for a Hotel. The new Room ajax form works correctly on the Room index page, but once I embed the new Room ajax form on a Hotel edit page, the form is submitted normally without using Ajax.
To create the new Room form, I use the following link on the Hotel edit.html.erb page:
<%#= link_to 'Add a Room', new_room_path(:hotel_id => #hotel.id), :remote => true, :class => 'new_room' %>
This loads the following form partial on to that same page:
<%= form_for #room, :remote => true, :html => { :class => "remote-form" } do |f| %>
<%= f.text_field :number %>
<%= f.text_field :size %>
<% if(params.has_key?(:'hotel_id')) %>
<% #hotel_id = params[:hotel_id] %>
<%= f.hidden_field :hotel_id, :value => #hotel_id %>
<% else %>
<%= f.collection_select(:hotel_id, Hotel.all, :id, :name) %>
<% end %>
<%= f.submit "Add this room", :class => 'room_create' %>
<%= link_to 'Cancel', '#', :class => "room_cancel" %>
<% end %>
And finally, I have the following in my create.js.erb (inside the rooms folder):
alert('Test creating a room');
var content = $('<%= escape_javascript(render(#room)) %>');
$("#room_list tbody").append(content);
The create.js.erb is not executed and the form is submitted regularly (non-ajax) and I finally arrive on the room show.html.erb page.
Why is the form be working correctly on the Units index page, but not on the associated Hotel edit page?
Even when you set :remote => true, Rails generates a form tag. Nested form tags are not supported by browsers and will result in unpredictable behavior.
You should rethink the views architecture here. Probably you can have the forms for the rooms outside of the form for the hotel, or maybe you can use fields_for and accepts_nested_attributes_for to edit children objects.
Here's a full example on how to use nested attributes: Nested Attributes Examples.
You cannot nest a form inside a form in HTML. When you click any submit button on a form, even if it's inside another form, only the outermost form will be properly submitted.
You can either use nested attributes to add the attributes for the room directly to the form, so that when the overall form is submitted so are all the rooms... or use a div and a link, instead of a form and a submit button.

Rails simple form different styles for different forms

I use the simple-form gem in a rails 3.1 project together with twitter bootstrap. I have several form views which all look fine. But now I like to style the text input field in one of the forms so it gets a bit smaller. The text input field is located in the edit form view of one of my controllers called "roles". The partial for the form looks like this:
= simple_form_for #role, :html => { :class => 'form-horizontal' } do |f|
= f.error_notification
= f.input :name
= f.input :description
.form-actions
= f.button :submit, :class => 'btn-primary'
= link_to t('.cancel', :default => t("helpers.links.cancel")), roles_path, :class => 'btn'
There is a style file under:
app/assets/stylesheets/roles.css.scss
which was created with the scaffold command. I tried to put some styling in here but this results in a change in every form of my application. Is there a good way to change the styling of a text input field only for one special form view with simple form? Where should I put the styling and how would the styling look like if I'd like to have the input text field in the size: width 100px to height 50px?
You need to know that even if you have a special CSS file just for roles. In the end, every CSS file is bundled up and served together. This means, that roles.css will be loaded on every page, which results in the behavior you described.
If you want to style a single form, you can do this by adding a class:
= simple_form_for #role, :html => { :class => 'form-horizontal roles-form' } do |f|
Now you can scope your CSS definitions to .roles-form and they will only apply to this single form.

Resources