Rails - multiple forms unintentionally using the same object - ruby-on-rails

I've got a page showing details for every #user. Each user has an enrolment, which can has a comment. When I e.g. do this:
<% #user.each do |u| %>
<% the_enrolment = Enrolment.where(user_id: u).first %>
<% end %>
Then in every iteration the enrolment is a different enrolment, as the user changes in every iteration. So far, so simple.
But when I pass this enrolment variable (while looping through) to a partial which contains a form, like this:
<%= render 'the_partial', enrolment: the_enrolment %>
With this form (in the partial view):
<%= form_for enrolment, :url => the_path, remote: true do |f| %>
<%= f.hidden_field :id %>
<%= f.text_area :comment %>
<%= f.submit "Save" %>
Then, in the finally rendered page, every form uses the same enrolment. (They all have the same id and every text_are is pre filled with the content of one of them. What am I doing wrong here?
The complete iteration looks like this:
#user.each do |u|
the_enrolment = Enrolment.where(user_id: u).first
<%= the_enrolment %> # correct id
<%= render 'the_partial', enrolment: the_enrolment %>
end
Thank you very much!
Update
Here is an update with the newest informations. The problem seems to be that the form is placed inside a twitter bootstrap modal. Here is the whole partial:
<%= enrolment.id %> # here it's the correct id
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Admin Comment</h3>
</div>
<%= form_for enrolment, :url => the_path, remote: true do |f| %>
<div class="modal-body">
<p>
<%= "enrolment in modal: #{enrolment.id}" %> # at this place the id is ALWAYS the id of the very first enrolment
<%= f.hidden_field :id %>
<%= f.text_area :comment_admin %>
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= f.submit "Save", class: "btn btn-success", id: "admin-comment-submit-button" %>
</p>
</div>
<% end %>
</div>
If I delete everything on this page concerning the modal, the form works.

Related

Problems with Modal in Rails opening the same object

I'm maintaining an older Rails 3.2.22 app and I'm trying to add a modal to pop up with a simple form to add a note.
Here is my view (cut down for readability)
<% #assigned.each do |call| %>
<%= link_to "Notes", '#ajax-modal', data: { toggle: "modal", target: "#note-modal" }, class: 'btn btn-small btn-inverse' %>
<%= render 'layouts/note_modal', :call => call %>
<% end %>
Here is my modal app/views/layouts/_note_modal.html.erb
<div id="note-modal" class="modal hide fade" tabindex="-1">
<div class='modal-header'>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title"><%= call.incident_number %> Notes</h3>
</div>
<div class='modal-body'>
<div class="modal-body-content">
<%= form_for(#note, url: call_note_calls_path, html: {class: "form-inline"}) do |f| %>
<%= f.text_field :message, :maxlength => 255 %>
<%= f.hidden_field :call_id, value: call.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.button "Add Note", class: 'btn btn-info btn-small', data: {disable_with: "<i class='icon-spinner'></i>Posting..."} %>
<% end %></div>
<div class="ajax-loader">
</div>
</div>
<div class='modal-footer'>
<button type="button" data-dismiss="modal" class="btn">Close</button>
</div>
</div>
When I load the page and there are several calls I click on the notes link, the partial renders in a modal and I can submit a note. The problem is if I have 10 calls on the screen no matter which notes link I click on it adds a note to the first call on the screen.
Am I passing locals incorrectly? I know this code is inside of the block so it should pull the call object and pass it as a local to the partial in the modal but it's not.
Any help is greatly appreciated.
I think the issue is that you render the modal each time for a note but they all have the same id. So you are always opening the first modal. Actually IMHO you just need to render the modal once and pass the note_id via an data attribute on the link which triggers the modal. So basically configure the modal via the caller.
I was able to figure this out on my own and still render the partial within the loop by calling an index as part of the target ID for the modal. Working code below.
<% #assigned.each_with_index do |call, index| %>
<%= link_to "Notes", '#note-modal', data: {toggle: "modal", target: "#note-modal#{index}" }, class: 'btn btn-small btn-inverse' %>
<%= render 'layouts/note_modal', call: call, index: index %>
<% end %>
<div id="note-modal<%= index %>" class="modal hide fade" tabindex="-1">
<div class='modal-header'>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title"><%= call.incident_number %> Notes</h3>
</div>
<div class='modal-body'>
<div class="modal-body-content">
<%= form_for(#note, url: call_note_calls_path, html: {class: "form-inline"}) do |f| %>
<%= f.text_field :message, :maxlength => 255 %>
<%= f.hidden_field :call_id, value: call.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.button "Add Note", class: 'btn btn-info btn-small', data: {disable_with: "<i class='icon-spinner'></i>Posting..."} %>
<% end %></div>
<% call.notes.each do |n| %>
<li><%= n.message %> added by <%= n.user.username %></li>
<% end %>
<div class="ajax-loader">
</div>
</div>
<div class='modal-footer'>
<button type="button" data-dismiss="modal" class="btn">Close</button>
</div>
</div>

How do I render the same partial multiple times on a page with locals

In my have app I have a concept of notes... On the page I list out all the notes with an edit button. This edit button opens up a modal for editing the note. This all works great except for one big problem. If I have 5 notes, when I click the first edit button, it edits the first note as expected... However if I click on the second edit button, it ALSO edits the first note INSTEAD of the second. Same for the third, etc. Basically no matter what edit button I click I am always editing the first note.
User controller
def show
#user = User.find(params[:id])
#notes = #user.notes.order('created_at DESC')
end
Index page
<% #notes.each do |note| %>
<td><%= note.body %></td>
........
<td>
<%= button_tag text, class: "btn btn-primary", data: {toggle: "modal", target: "#edit_note"} %>
<%= render partial: "edit_note_modal", locals: { note: note } %>
</td>
<% end %>
Note Modal
<div class="modal fade" id="edit_note" tabindex="-1" role="dialog" aria-labelledby="edit_note" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Edit Note</h4>
</div>
<div class="modal-body">
<%= form_for note do |f| %>
<div class="form-group">
<label for="keyword">Keyword</label>
<%= select_tag :keyword, options_for_select(<SOME FUNCTION>, selected: note.keyword ), class:"form-control" %>
</div>
<div class="form-group">
<label for="body">Body</label>
<%= text_area_tag :body, note.body , class:'form-control' %>
</div>
<div class="modal-footer">
<%= submit_tag "Update Note", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
That is because you use the same ID and ID should be uniq so when it search for the ID in the index page once it hit the first Note with that ID edit_note it will open it, what you can do is have different Id for each view as following:
index page:
<%= button_tag text, class: "btn btn-primary", data: {toggle: "modal", target: "#edit_note_#{note.id}"} %>
Note Modal:
<div class="modal fade" id="edit_note_#{note.id}" tabindex="-1" role="dialog" aria-labelledby="edit_note" aria-hidden="true">
Note how the id now is edit_note_#{note.id} and the edit button try to open model with same target edit_note_#{note.id}

how to refresh a partial after an edit has been made in rails

I am making an ecommerce website page.It consists of two parts.A sidebar having a list of all products and a right column where the details of the product is shown once the product is selected from the list.
I am making ajax calls to load the various partials of the application. The sidebar having all the products is index,the one on right having the details of products is show which shows the details of the product selected.
Now when I edit the product(through a modal) how do I automatically reload the respective partials so that the new changes are reflecte.For me to see the changes I have to refresh the pages currently,how do i ensure the partials are automatically loaded once I click submit on the edit modal.
My index.html.erb looks like
<div class="container">
<div class="row row-offcanvas row-offcanvas-left">
<div class="col-xs-8 col-sm-4 sidebar-offcanvas" id="sidebar" role="navigation">
<div class="well sidebar-nav">
<ul class="nav">
<div class="jumbotron well">
<h3>Product Listing Application</h3>
</div>
<%= link_to "New Product", new_product_path, remote: true, class: "btn btn-primary" %>
<div class="list-group">
<%= render "index" %>
</div>
</ul>
</div><!--/.well -->
</div><!--/span-->
<div class="col-xs-10 col-sm-8">
<div id="page-content-wrapper">
<div class="page-content">
<div class="col-md-12 product-info" id="product-details">
</div>
</div>
</div>
<div id="product-modal" class="modal fade"></div>
</div>
</div><!--/row-->
</div>
My _index.html.erb is
<% #products.each do |product| %>
<%= link_to product_path(product), remote: true, class: "list-group-item" do %>
<h4 class="list-group-item-heading"><%= product.name %></h4>
<p class="list-group-item-text"><%= number_to_currency product.price %></p>
<% end %>
<% end %>
My _edit.html.erb is
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3><%= "Editing #{#product.name}" %></h3>
</div>
<%= render "form" %>
</div>
</div>
My _form.html.erb is
<%= form_for #product, remote: true, html: { class: "form-horizontal", style: "display:inline;" } do |f| %>
<div class="modal-body">
<ul class="errors"></ul>
<div class="control-group">
<%= f.label :name, class:"control-label" %>
<div class="controls">
<%= f.text_field :name %>
</div>
</div>
<div class="control-group">
<%= f.label :price, class: "control-label" %>
<div class="controls">
<%= f.text_field :price %>
</div>
</div>
</div>
<div class="modal-footer">
<%= f.submit class: "btn btn-primary" %>
<%= link_to "Cancel", "#", class: "btn", data: {dismiss: "modal"} %>
</div>
<% end %>
You can use
location.reload();
on your js.erb for refresh your partial, or for your instance vaiable
you can directly use
#post = #post.reload # in palce of #post you can your instance variable
create a js file same name as your page
add below code in it
edit.js.erb
$("<%= escape_javascript render(:partial => 'ur_partial_page_name') %>").dialog();
$('#new_comment_link').hide();`
in your edit page form where u r calling modal dialog
<%= link_to "edit", edit_product_path (#product, :format => :js), :remote => true %>
In your product controller
def edit
#source = Product.find(params[:id])
respond_to do |format|
format.html # edit.html.erb
format.xml { render :xml => #product }
format.js
end
end
and in your partial form
<%= form_for (#product, :remote => true) do |f| %>

Rails 4.0.4 custom form_for route

I'm trying to map a form_for to a specific controller and action. I've got the resources: apikey in the routes. All the solutions I've found don't seem to work. The form is placed inside a view of which the parent folder name doesn't correspond to the correct controller. Here is my form with my not working solution:
<%= form_for #key, url: { controller: :apikey, action: :update }, remote: true do |f| %>
<%= f.label :userkey, "Key" %>
<%= f.text_field :userkey %>
<%= f.submit "Update" %>
<% end %>
Here is my controller:
class ApikeyController < ApplicationController
def index
end
def update
respond_to do |format|
if #key.update(apikey_params)
format.js
else
format.html { render action: 'edit' }
end
end
end
private
def apikey_params
params.require(:apikey).permit(:userkey)
end
end
This is the log I get in the console:
Started GET "/accounts?utf8=%E2%9C%93&_method=patch&apikey%5Buserkey%5D=thekey&commit=Update"
As you can see, it doesn't call the apikey but the accounts controller. What am I doing wrong?
Update
A little weird, as I didn't really change anything, I now get this error when opening the site:
No route matches {:action=>"update", :controller=>"apikey"}
This is my rake routes:
apikey_index GET /apikey(.:format) apikey#index
POST /apikey(.:format) apikey#create
new_apikey GET /apikey/new(.:format) apikey#new
edit_apikey GET /apikey/:id/edit(.:format) apikey#edit
apikey GET /apikey/:id(.:format) apikey#show
PATCH /apikey/:id(.:format) apikey#update
PUT /apikey/:id(.:format) apikey#update
DELETE /apikey/:id(.:format) apikey#destroy
Update 2
Originally I had the form inside a bootstrap modal, like this:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Change API key</h4>
</div>
<div class="modal-body">
<form role="form">
<div class="form-group">
<%= form_for #key, method: "post", remote: true do |f| %>
<%= f.label :userkey, "Key" %>
<%= f.text_field :userkey, class:"form-control", id:"apikeyinputfield" %>
<%= f.submit "Update", class: "btn btn-success btn-sm" %>
<% end %>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" id="submitnewapikey" data-dismiss="modal" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
If I delete the surrounding modal, the form automatically to map to the correct controller and action. This is not the case when surrounded by the modal. Really weird. Maybe the modal JS code messes up the form_for JS code.
You don't actually need to specify the url in form_for.
If no url is specified form_for will automatically identify which controller and method based on the #key parsed to it, regardless of what view the form is located.
<%= form_for #key, remote: true do |f| %>
<%= f.label :userkey, "Key" %>
<%= f.text_field :userkey %>
<%= f.submit "Update" %>
<% end %>
the piece code above can have the following outcomes:
if #key is a new record ( #key.new_record? returns true):
The form will send the request to ApikeyController create action
if #key is a not a new record ( #key.new_record? returns false), which is your case:
The form will send the request to ApikeyController update action
More info can be found here.
Hope this can help you.

Rails partial form in a form

I have a Rails app with Expenses that belongs_to Vendors.
While the user is adding a new Expense, they might need to add a new Vendor.
I thought I could just add a button and a Vendor partial to the Expense form.
Like this:
<%= simple_form_for #expense, :html => {:class => 'form-horizontal'} do |f| %>
<div class="span5">
<a data-toggle="modal" href="#vendorform">
<p class="pull-right btn btn-primary btn-mini">New Vendor</p></a>
<%= render :partial => "vendors/vendorform" %>
</a>
<%= f.association :vendor, :label_method => :vendor_name, :label => 'Vendor', collection: Vendor.order('vendor_name ASC') %>
The _vendorform.html.erb looks like this:
<div id="vendorform" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="vendorformLabel" aria-hidden="true">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h4 id="vendorformLabel">Add Vendor</h4>
</div>
<div class="modal-body">
<%= simple_form_for Vendor.new do |f| %>
(bunch of fields)
</div>
<div class="modal-footer">
<%= f.submit 'Save Vendor', :class => 'btn btn-mini btn-primary' %>
<a class="btn btn-mini" data-dismiss="modal" href="#">Close</a>
<% end %>
</div>
</div>
This partial shows up OK. But, the Vendor record doesn't get created.
The submit of the partial actually somehow triggers the submit for the Expense. The page comes back with all of the required Expense fields red.
I think it's posting to the Expenses controller when the f.submit button in the Vendor partial is pressed !!!
Do I need something in the Expense controller?
Or is there a better way?
Thanks for the help!
Are you sure the vendor partial is in the same folder as the expense form? If not you should have
<%= render :partial => "folder/vendorform" %>
When you have nested attributes, you should use the simple_fields_for method which help manage associations. Then, remove the submit button for the vendor form and add it to the expense form instead. So the vendor form would be -
<div class="modal-body">
<%= simple_form_for Vendor.new do |f| %>
(bunch of fields)
<% end %>
</div>

Resources