Rails 3 - checkbox for create (opposite of _destroy) - ruby-on-rails-3

I have a Query model with a has_many relationship to OutputFields. In my query controller's new function I build several OutputFields within the query instance. In my form, I want each checkbox to determine whether the object is saved (a check means save this instance of OutputField to the database). How can I do this?
my models:
class Query < ActiveRecord::Base
attr_accessible :description, :name
has_many :output_fields, :dependent => :destroy
accepts_nested_attributes_for :output_fields
end
class OutputField < ActiveRecord::Base
attr_accessible :query_id, :column_name, :table_name
belongs_to :query
end
relevant sections of my queries controller. Structure is another model.
# GET /queries/new
# GET /queries/new.json
def new
#query = Query.new
Structure.columns.each do |column|
#query.output_fields.build( :table_name => Structure.table_name, :column_name => column.name )
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #query }
end
end
Finally, my view. Right now I'm linking the checkbox to the destroy attribute, which I think will do the exact opposite of what I want.
<%= form_for(#query) do |f| %>
<%= f.fields_for :output_fields do |builder| %>
<div class="field">
<%= builder.check_box :_destroy %>
<%= builder.label :_destroy, builder.object.column_name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If it's not obvious, I'm trying generate a user interface for a simple query builder. This is my first rails app, so any advice is appreciated.

By default the value of the check_box form helper is to set the checked_value to '1' and the unchecked_value to '0'. So to reverse the behaviour of the destroy checkbox, just switch these values around.
<%= builder.check_box :_destroy, {}, '0', '1' %>

Related

Rails nested form with multiple entries

I have a Sezzion model:
attr_accessible :description
has_many :session_instructors, :dependent => :destroy
has_many :instructors, :through => :session_instructors
accepts_nested_attributes_for :session_instructors
accepts_nested_attributes_for :instructors
Instructor model:
attr_accessible :bio
has_many :sezzions, :through => :session_instructors
has_many :session_instructors, :dependent => :destroy
SessionInstructor model:
attr_accessible :instructor_id, :sezzion_id
belongs_to :sezzion
belongs_to :instructor
Lastly, User model:
has_many :sezzions
has_many :instructors
I'm trying to create a form for Sezzion with nested form for SessionInstructor which has multiple select option for Instructors.
How can I do the following:
nested form for SessionInstructor
use multiple select option to get all the selected Instructor's instructor_id
hidden field to pass in the created/updated session_id with each select instructor
I have the following code as of now:
<%= form_for(#sezzion) do |f| %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.label :instructors %>
<%= fields_for :session_instructors do |f| %>
<select multiple>
<% current_user.instructors.each do |instructor| %>
<option><%= instructor.name %></option>
<% end %>
</select>
<% end %>
<%= f.submit %>
<% end %>
Thank you so much!
This is something that seems ridiculously hard in Rails.
I think something like this might work:
<%= f.fields_for :session_instructors do |si| %>
<%= si.collection_select :instructor_ids, current_user.instructors, :id, :name, multiple: true>
<% end %>
This should create a form element which will set sezzion[session_instructors_attributes][instructor_ids].
Although I'm not sure if that's actually what you want. I've never tried this using a multi select. If it doesn't work, you could also try getting rid of the fields_for and just using f.collection_select. If you're willing to use a checkbox, I can show you how to do that for sure.
I hope that helps.
Edit:
Here's how I would usually do it with a check_box:
<%= f.fields_for :session_instructors do |si| %>
<%= si.hidden_field "instructor_ids[]" %>
<% current_user.instructors.each do |i| %>
<%= si.check_box "instructor_ids[]", i.id, i.sezzions.include?(#sezzion), id: "instructor_ids_#{i.id}" %>
<%= label_tag "instructor_ids_#{i.id}", i.name %>
<% end %>
<% end%>
There are a couple "gotchas!" with this method. When editing a model, if you deselect all checkboxes then it won't send the parameter at all. That's why the hidden_field is necessary. Also, you need to make sure each form element has a unique id field. Otherwise only the last entry is sent. That's why I manually set the value myself.
I copy pasted and then edited. Hopefully I got the syntax close enough where you can get it to work.
FINAL EDIT:
Per Sayanee's comment below, the answer was a bit simpler than I thought:
<%= f.collection_select :instructor_ids, current_user.instructors, :id, :name, {}, {:multiple => true} %>
#Sayanee, can you post how your instructors, sezzions table look like. Also for note, you can not get instructor_ids from Instructor object, hence you are getting "undefined method" error. With the current association that you shared, you can get instructor_ids from a Sezzion object. So you need to loop through current_user.sezzions in stead of current_user.instructors.
This is a way to implement fields_for nested form with html multiple_select in case of a has_many :through association. Solved it by doing something like this. The form view:
<%= form_for(#sezzion) do |f| %>
...
<%= fields_for :session_instructors do |g| %>
<%= g.label :instructor, "Instructees List (Ctrl+Click to select multiple)" %>:
<%= g.select(:instructor_id, Instructor.all.collect { |m| [m.name, m.id] }, {}, { :multiple => true, :size => 5 }) %>
<%= g.hidden_field :your_chosen_variable_id, value: your_chosen.id %>
<% end %>
...
<%= f.submit %>
<% end %>
Note:Since the #sezzion would not be saved at the time of generating the form you cannot pass that id (#sezzion.id) in place of your_chosen.id through the form. You could handle that save in the controller.
Make sure that your controller Initializes the Variables while generating the form: Your def new could look something like this:
def new
#sezzion = Sezzion.new
#sezzion.session_instructor.build
#sezzion.instructors.build
end
Now the create controller has to be able to accept the strong params required for the multiple select, so the sezzion_params method may look something like this:
def sezzion_params
params.require(:sezzion).permit(:description, :any_other_fields,
:session_instructors_attributes =>
[:instructor_id => [], :your_chosen_id => Integer])
end
In the create function, the first session_instructor variable is linked to the #sezzion instance variable through our new function. The other session_instructors in our multiple select must be built after the Sezzion instance is saved, if you want to pass in the created #sezzion.id with each select instructor. .
def create
#sezzion = Sezzion.new(sezzion_params)
#startcount=1 #The first element of the array passed back from the form with multiple select is blank
#sezzion.session_instructors.each do |m|
m.instructor_id = sezzion_params["session_instructors_attributes"]["0"]["instructor_id"][#startcount]
m.your_chosen_variable_id = your_chosen.id
#startcount +=1
end
if #sezzion.save
sezzion_params["session_instructors_attributes"]["0"]["instructor_id"].drop(#startcount).each do |m|
#sezzion.session_instructors.build(:instructor_id => sezzion_params["session_instructors_attributes"]["0"]["instructor_id"][#startcount],
:your_chosen_variable_id => your_chosen.id).save
#startcount += 1
end
flash[:success] = "Sezzion created!"
redirect_to root_url
else
flash[:danger] = "There were errors in your submission"
redirect_to new_sezzion_path
end
end

Rails 3 Cocoon link_to_add_association Renders Partial Twice

My partial gets rendered twice instead of only once, as expected. Any thoughts?
Here's my Person view
<%= simple_nested_form_for(#person) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name %>
<h3>Records by year</h3>
<div id='records'>
<%= f.simple_fields_for :records do |record| %>
<%= render 'record_fields', :f => record %>
<% end %>
<div class='links'>
<%= link_to_add_association 'New Record', f, :records, :class => 'btn' %>
</div>
</div>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Models (removed things such as constants and validations):
class Person < ActiveRecord::Base
attr_accessible :name, :records_attributes
has_many :records, :dependent => :destroy
accepts_nested_attributes_for :records, :reject_if => :all_blank, :allow_destroy => true
end
class Record < ActiveRecord::Base
attr_accessible :price, :status, :year, :person_id
belongs_to :person
end
My _record_fields.html.erb partial looks like this:
<div class='nested-fields well'>
<%= f.input :price %>
<%= f.input :year %>
<%= f.input :status, :collection => record_statuses, :include_blank => false %>
<%= link_to_remove_association "Remove", f %>
</div>
An interesting issue is that, if I change where the partials are generated (so 'after' instead of the default 'before' the link_to_add_association link), it generates a partial after the button, but the duplicate is generated before the link_to_add_association link.
The only similar issues reported on here I could find were with caching in production. This is happening in development, and my caching is turned off (by default).
Am I missing something? Can anyone help?
Edit:
Looking at the cocoon JavaScript, it seems the click event is called twice for one click (tested it with $('.add_fields').click(), which triggers $('.add_fields').live('click', function() {...} ) twice. I'm still at a loss as to why this might be happening. Input thoroughly appreciated.
Edit #2:
Controller:
# GET /persons/new
# GET /persons/new.json
def new
#person = Person.new
# #person.records.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #person }
end
end
# GET /persons/1/edit
def edit
#person = Person.find(params[:id])
end
I was having this same issue.
My problem was I requiring the cocoon javascript twice.
Once in my application.js
// app/assets/javascripts/application.js
//= require cocoon
and once in my application layout
/ app/views/layouts/application.html.haml
= javascript_include_tag :cocoon
after removing the include tag from my layout it began working as expected
Had the same issue, found that in my application layout (app/views/layouts/application.html.erb) I had already included application, and in application.js I had included cocoon. When including application.js in my view with cocoon, cocoon would fire twice.
(Same as above, but slightly different as I didn't explicitly specify cocoon in my application.html.erb, I specified application.js which included cocoon)
This happen when from application.js, you require two times cocoon, commonly, when you try change of jQuery to vanilla Javascript

Adding fields to nested forms

So I have a model called City and it has_many :places and it accepts_nested_attributes_for :places. Each Place belongs_to :category. When I render a form for a City I have f.fields_for :places do |place| and I do it like this:
<% f.fields_for :places do |place| %>
<%= render "place_fields", :f => place
<% end %>
My _place_fields.html.erb contains the folowing:
<div class="place_header"><%= f.object.category.name %></div>
<div><%= f.label :name %>: <%=f.text_field :name %> </div>
<div><%= f.text_area :description %> </div>
But the problem apears when I try to add a new place. First of all I want to bring up a simple select form to select a category for the new place, and then render that same partial based on the category_id.
I do that inside the same action:
def add_place
if params[:category_id]
#place = Place.new(:category_id => params[:category_id])
respond_to do |format|
format.html { return nil }
format.js {
#here comes the render
}
end
else
render_message :header => "Choose category", :partial => "category_select", :over => 10
end
end
But if I try to do $("#places_tab").append("<%= escape_javascript(render :partial => "place_fields", :f => #place %>"); it gives an error, wich is expected.
Once again: I need to render the fields for that new Place and just don't know how to do that.
UPDATE
Received some advice on passing the original City Formbuilder to the action and rendering that Place right from that builder, but don't have any idea of how to do that.
The problem is that you are passing an instance of the Place model (#place) as the form builder instead of the form builder itself.

Rails3 Associations and nested attributes

I am having trouble when it comes to saving/creating 2 objects at once and associating them to one another. Currently I am doing it in a 'hackish' sort of way by not using nested forms and just passing the parameters for both objects separately (from the view.) Then I connect them in the controller here is my code:
Models
class Post < ActiveRecord::Base
belongs_to :user
has_one :product
accepts_nested_attributes_for :product, :allow_destroy => true
end
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
View
<%= form_for(#post) do |f| %>
<div id="post_field">
<%= f.text_area :content %>
</div>
<div id="post_link_previewer" class="clearfix">
<%= fields_for :product do |prod| %>
<%= prod.text_field :name %><br />
<%= prod.text_area :description, :rows => 2 %><br />
<%= prod.text_field :image_url %><br />
<%= prod.text_field :original_url %>
<% end %>
</div>
<div id="submit" class="clearfix">
<%= f.submit "Post" %>
</div>
<% end %>
PostsController
def create
#user = current_user
#post = #user.posts.create(params[:post])
#product = Product.create(params[:product])
#post.product_id = #product.id
respond_to do |format|
if #post.save
format.html { redirect_to(root_path, :notice => 'Post was successfully created.') }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
So when a user makes a post, they can attach a 'product' to that post if they want. The current way I am doing it makes a lot of sense. When I looked at nested form tutorials and see them using build methods I start to get a little confused as to what is going on. Can you help me understand the best way of linking these 2 objects upon create? Is it best to use nested form fields? I feel the current way I am doing it isn't as efficient as it should be.
Yes, you should use nested forms. There is a reason as to why they were built. They ease the process of managing associations and creating nested objects in a single go.
The build method builds an object (it calls the .new() method for the object) and then you can use it.
I advise you to start with a simple example of nested forms and play around with it for an hour or two. This way, you'll have a better understanding of what's happening underneath.
I think, in this case, self-learning by playing would help you a lot, instead of someone just telling you why nested forms are better.
To get you started, refer to nested-attributes-in-rails.

how to update multiple models with rails form

I have following two models
class Office < ActiveRecord::Base
has_many :locations, :dependent => :destroy
end
class Location < ActiveRecord::Base
belongs_to :office
end
I have a new.html.erb for the office model and the below code in OfficeController
def create
#office = Office.new(params[:deal])
if #office.save
redirect_to office_url, :notice => "Successfully created office."
else
render :action => 'new'
end
end
How can I add fields for Location model in new.html.erb of Office?
I want to be able to have fields for locations in the same form.
You'll have to use nested attributes to do this. Fortunately, Rails makes it pretty easy. Here's how to do it:
First, signify to Office that you're giving it Location fields as well by adding this line:
accepts_nested_attributes_for :location.
Now, in new.html.erb, add the fields that you want. Say we want to have city and state:
<%= f.fields_for :location do |ff| %>
<%= ff.label :city %>
<%= ff.text_field :city %>
<%= ff.label :state %>
<%= ff.text_field :state %>
<% end %>
That's it!