Is there a way to get the `id` of a nested_form field helper element? - ruby-on-rails

I am trying to create the for attribute for a label in a nested form (Using nested_form). Is there a way to get the id of a corresponding f.checkbox?
HAML:
= label_tag '???', "Set as On", class: primary_btn
= f.check_box :is_on
Additional Information:
The current Model structure is like Post has many Images with field is_on
So I would like to create a nested field group like:
<label class="primary_btn" for="post_images_attributes_0_is_on">Set as primary</label>
<input id="post_images_attributes_0_is_on" name="post[images_attributes][0][is_on]" style="display:none;" type="checkbox" value="1">

The trick is to use fields_for. It gives you a "scoped" form builder instance which creates inputs for the nested fields.
= form_for (:post) do |f|
# ... a bunch of fields
= f.fields_for :images do |builder|
= builder.label :is_on, "Set as primary"
= builder.check_box :is_on
However your solution has some real gotchas:
Every time you change the primary image you need to update all the post.images to ensure that only one image has the is_on flag.
You need to do primary_image = post.images.where(is_on: true)
It won't work if the image can belong to many posts.
A better solution is create a special relation to the primary image on Post.
class Post < ActiveRecord::Base
has_many :images
has_one :primary_image, class_name: 'Image'
end
This would store the primary image as an integer in posts.primary_image_id instead of as a boolean flag on images.
We can use collection_select to get select tag to display the primary image attribute.
= form_for (#post) do |f|
# ... a bunch of fields
= f.fields_for :images do |builder|
# ...
= f.collection_select(:primary_image, #post.images, :id, :name)
This admittedly is not really optimal from a user experience perspective. A solution which requires javascript would be to have a hidden field for :primary_image and update its value when the user clicks the checkbox. If you are unsure how to do this please create a new question since its out of the scope of your original question.

Related

Creating a form for a has_and_belongs_to_many relationship

I've read through a lot of posts regarding this topic, but not one actually provides a good answer.
I have a class A and a class B who are related through a has_and_belongs_to_many relationship.
class A < ApplicationRecord
has_and_belongs_to_many :bs
end
class B < ApplicationRecord
has_and_belongs_to_many :as
end
What I need is a form for class A showing a selection field with all the instances of B to select. Also, when editing and instance of A, the form should present a list of the related instances of B and a way to mark them for removal.
I have tried creating the list of existing instances by providing a hidden field with the id for each instance of B. And I have created a selection field using the select_tag. The code looked something like that:
= form_for #a do |f|
.field
= f.label :name
= f.text_field :name
.field
- #a.bs.each_with_index do |b, i|
= b.name
= hidden_field_tag "a[b_ids][#{i}]", b.id
.field
= select_tag "a[b_ids][]", options_from_collection_for_select(#bs, "id", "name")
.actions
= f.submit 'Save'
This worked just fine when creating the new instance of A. But when I tried to edit it, there seems to be a problem making the execution fall back to using POST instead of PATCH. And since with there is now route for POST when editing/updating this obviously ended in an exception.
So I wonder if there is any clean way to create the form I need?

semantic_field_for for arbitrary attribute

I am quit new to rails. I have been using formtastic in my project and I find it quite easy to deal with the form objects. I have a small problem which I hope to clear out here.
I want to create a form for arbitrary objects and a has_many type of nested form for it. What I mean is semantic_form_for does not use any model instead uses symbol for creating form and this form now has to have a to_many type of semantic_fields_for. This is how my code looks,
= semantic_form_for :company do |f|
= f.inputs "company" do
= f.input :name
= f.input :enterprise_code
= f.semantic_fields_for :email do |e|
= f.inputs "email" do
= f.input :address
The form above is not associated to any model. I will pick these attributes in the controller and assign it individually. The email fields in the form has to be like has_many. Now, it is like one to one. How can this be achieved.
I used formtastic only once so i might be wrong but i don't think there's anything mentioned that you can use it only for one type of association. It only says that you for nested forms we can use semantic_fields_for :model and then both model's must be setup correctly with accepts_nested_attributes_for

Cannot retrieve lookup values correctly

I've built a lookup table in my Rails application.
It is a table that stores lookup text values for drop-down pickers or possibly check boxes. I want the lookup table to have a view associated so the values can be easily edited. I also may want to share lookup values among multiple models for a single field in the future.
So far I've managed to get it to work for the selection of values, but then displaying the text value again on a show or index view has been problematic.
This is how I built the lookup table
rails g scaffold Lookup field_name lookup_text table_name note
In the edit.html.erb where there is a lookup on a field, I've got code like this, which works and allows me to pick from a list.
<div class="field">
<%= f.label :status %><br />
<%= f.collection_select :status, Lookup.find(:all,:conditions => ["table_name = 'course' and field_name = 'status'"]), :id, :lookup_text, include_blank: true,:prompt => "Status" %>
</div>
That all works fine. When I try to display it back I cannot find the correct syntax. The best I have found is this:
(in the controller)
#status = Lookup.where(:id => #course.status).pluck(:lookup_text)
(in the view)
<p>
<b>Status:</b>
<%= #status %>
</p>
I think I am getting the entire object. It displays like this:
Status: ["Active"]
My questions are:
(1) How do I display the value only?
(2) Is this the best approach?
I've had a look at these and other SO questions, but none are really what I am looking for:
Rails Polymorphic with Lookup Table
Implementing a lookup table in Rails
EDIT
OK this works, but it doesn't look like it is the correct solution. Has anyone got a better way of doing this?
#status = Lookup.where(:id => #course.status).pluck(:lookup_text)[0]
Just another way to show the value is #status = Lookup.find(#course.status).lookup_text
Why not to try use classes for different lookups:
class CourseStatus < ActiveRecord::Base
set_table_name "lookups"
default_scope where("table_name = 'course' and field_name = 'status'")
end
class Course
belongs_to :course_status
end
You then can use:
CourseStatus.all # e.g. to fill select options
Course.first.course_status.lookup_text # => "Active" or smth else
Or without classes:
class Lookup
def self._by_table_and_field(table, field)
['table_name = ? and field_name = ?', table, field]
end
scope :by_table_and_field, lambda { |table, field|
where(Lookup._by_table_and_field(table, field))
}
end
class Course
belongs_to :status, class_name: 'Lookup', conditions: Lookup._by_table_and_field('course', 'status')
end
Lookup.by_table_and_field('course', 'status').all
Course.first.status.lookup_text

ruby on rails how to use FormOptionHelpers to create dynamic drop down list

I have checked some tutorials but I got confused by the parameters in this method
collection_select (object, attribute, collection, value_method, text_method, options = {}, html_options ={})
I have a map model includes: :area, :system, :file
and I want to read :area from database to a drop down list, and let user choose one
I already did #map = Map.all in the view
what the method should be?
especially the parameter "attribute". In a lot tutorials, people put "id" here. But I don't know what "id" is, and in my situation I don't need any other value, just the "area".
Im not exactly sure what you are asking here but if you are trying to make a dropdown selection for use in an html form will this example help you at all?
<% nations = {'United States of America' => 'USA', 'Canada' => 'Canada', 'Mexico' => 'Mexico', 'United Kingdom'=> 'UK'} %>
<% list = nations.sort %>
<%= f.select :country, list, %>
Here nations is a hash of countries then list becomes the sorted copy of that hash. An html dropdown is then created as a part of the form "f". ":country" is the part of the model that the data is connected to while list is the options to populate the dropdown with
It's not clear from your question what the model is that's being populated with the area.
Typically, collection_select is used between related models.
eg.
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :category
end
When selecting the 'category' for a product, your view would have something like:
<%= f.collection_select(:category_id, :id, Category.all, :name, include_blank: true) %>
What this does is specify the Product.category_id as the attribute being populated with the value of Category.id. The values come from the Category.all collection, and with Category.name being the item displayed in the select. The last (optional) parameter says to include a blank entry.
Something like the following is probably what you need:
<%= f.collection_select(:map_id, :id, #map, :area) %>
However, if the model you're trying to populate has an area attribute (instead of an ID linking to the map), you might need to use:
<%= f.collection_select(:area, :area, #map, :area) %>
This specifies that the area attribute of the receiving table will be populated with Map's area attribute, which is also being used as the "description" in the select.

How to pass foreign key attributes down through a nested form in Rails 3

I have three models:
class Client < ActiveRecord::Base
has_many :balancesheets
has_many :investment_assets, :through => :balancesheets
class Balancesheet < ActiveRecord::Base
belongs_to :client
has_many :investment_assets, :dependent => :destroy
accepts_nested_attributes_for :investment_assets, :allow_destroy => true
class InvestmentAsset < ActiveRecord::Base
belongs_to :balancesheet
belongs_to :client
I have two questions that have to do with the foreign key client_id. First, when I create a new balancesheet, I use collection_select to select the client from the list. I would rather put the new balancesheet link on the client show page and just pass the client id through to the form so I don't have to choose a client from a list or type it in a field. So first, how do I do that?
Second, the investment_asset model is nested in the balancesheet form. Everything works just fine, except the client_id attribute for the investment_asset is blank. Im not sure why because my associations seem to be okay. So the question is, how do I pass this client_id attribute down through the nested form? I can post models or controllers, just let me know.
UPDATE I have since found the answer to my first question here. However, I am still trying to figure out the second part based on that answer, which is, how do I pass this client_id down through a nested form? To show how it worked passing user id when creating a balancesheet, here is the client show page link:
<%= link_to 'New BalanceSheet',new_balancesheet_path(:id => #client.id) %>
In the balancesheet form I have a hidden field:
<%= f.hidden_field :client_id %>
And in the Balancesheet Controller this is the new action:
#balancesheet = Balancesheet.new(:client_id => params[:id])
This works just fine. So for an investment_asset I am using Ryan Bates nested_form gem which has a little bit different syntax for a link. So inside the balancesheet form the link to add a new investment_asset is:
<%= f.link_to_add "Add asset", :investment_assets %>
I can't figure out how to pass the user id like I did on the balancesheet with:
(:id => #client.id)
I can put the same thing in a new action in the investment_asset controller and add a hidden field, but I'm not sure how to pass it in on the link. Thoughts?
This might be a total hack for all I know, but all I know is very limited. What I ended up doing here was user jQuery to take the id from the balancesheet and force it into a hidden field for investment_asset. jQuery:
// get the value from the balancesheet hidden field that contains the user_id value
var balsheetclientid = jQuery('#hiddenid').attr('value');
// insert it into the value attribute in the hidden field with class name .iaclientid
jQuery('.iaclientid').val(balsheetclientid)
Then my hidden field looks like this:
<%= f.hidden_field :client_id, :class => 'iaclientid', :value => '' %>
It works just fine. Hopefully that's a valid way of doing it.

Resources