rails simple_form collection use - ruby-on-rails

I have problem.
I want to my posts/new.html.erb join dropdown.
I have two model post and category.
I hope when new post can choose my category.
posts/new.html.erb/
<%= simple_form_for #post do |f|%>
<%= f.input :category_id, as: :select %>
<% end %>
helper/posts.helper.rb
def collect_category
#cat_arr = []
Category.all.each do |cat|
#cat_arr = cat
end
return #cat_arr
end
I can't understand simple_form collection
Please help me, thx!

On your Post model, make sure you have:
belongs_to :category, class_name: "Category"
And your Category model, put:
has_many :posts, class_name: "Post"
Now on your form, you can do:
<%= f.association :category, as: :select %>
Optional: collection: Category.all(order: 'name') or whatever you want to display it by and order if you want.
You'll probably have to add attr_accessor for category_id on your Post model as well.

Related

Rails polymorphic association won't save _type

I have a few models in my project : Request, Work, Car and Employee. Work is an intermediate model between Request and Car/Employee.
Here are the associations:
Request
has_many :works, dependent: :destroy
def performers
works.map {|x| x.performer}
end
Work
belongs_to :request
belongs_to :performer, polymorphic: true
Car
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
Employee
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
View used to create works:
<%= form_for([#request, #work]) do |f| %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) if #request.type == "StaffRequest" %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) if #request.type == "CarRequest" %>
<%= f.submit 'OK' %>
<% end %>
Work controller
def new
#work = #request.works.new
end
def create
#work = #request.works.new(work_params)
end
def work_params
params.require(:work).permit(:performer_id, :request_id)
end
The problem is that my performer_type column is always empty, it does not save the class name. What can be the problem? Any ideas?
It's empty because you did't pass it, you should add a hidden field for you form:
<%= form_for([#request, #work]) do |f| %>
<% if #request.type == "StaffRequest" %>
<%= (f.hidden_field :performer_type, value: "Employee") %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) %>
<% elsif #request.type == "CarRequest" %>
<%= (f.hidden_field :performer_type, value: "Car") %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) %>
<% end %>
<%= f.submit 'OK' %>
<% end %>
Beside :performer_id, you have to pass the :performer_type also, one way to do this is via the form select_tag :
def create
#work = #request.works.new(work_params)
end
def work_params
# use :performer if you use :performer as in the select form field
params.require(:work).permit(:performer, :request_id)
# OR
# use :performer_id & :performer_type if you also use the hidden field
params.require(:work).permit(:performer_id, :performer_type, :request_id)
end
There is a good example (for Rails 4.2) of using a single select form field for polymorphic so you can write like:
<%= f.grouped_collection_select :global_performer, [ Car, Employee ], :all, :model_name, :to_global_id, :name %>
How to create grouped select box in Rails for polymorphic association using Global ID?

Rails - Manipulate has_many with join model through single form

I have the following three models:
class Site < AR::Base
has_many :installed_templates, :as => :installed_templateable, :dependent => :destroy
accepts_nested_attributes_for :installed_templates, :allow_destroy => true, :update_only => true, :reject_if => lambda { |t| t[:template_id].nil? }
end
class Template < AR::Base
has_many :installed_templates, :inverse_of => :template
end
class InstalledTemplate < AR::Base
belongs_to :template, :inverse_of => :installed_template
belongs_to :installed_templateable, :polymorphic => true
end
The business logic is that several Templates exist when I create a Site and I can associate as many as I'd like by creating an InstalledTemplate for each. A Site can only have unique Templates - I can't associate the same Template twice to a single Site.
I have the following on the form for Site:
<% Template.all.each_with_index do |template| %>
<%= hidden_field_tag "site[installed_templates_attributes][][id]", Hash[#site.installed_templates.map { |i| [i.template_id, i.id] }][template.id] %>
<%= check_box_tag "site[installed_templates_attributes][]]template_id]", template.id, (#site.installed_templates.map(&:template_id).include?(template.id) %>
<%= label_tag "template_#{template.id}", template.name %>
<% end %>
The above is the only thing that seems to work after lots of experimentation. I wasn't able to achieve this at all using the form_for and fields_for helpers.
It seems like a pretty straight forward relationship and I'm afraid I'm missing something. Anyone have advice on how to accomplish the above in a cleaner fashion?
Thanks
Try the following
<% form_for #site do |f| %>
<%f.fields_for :installed_templates do |af|%>
<%= af.text_field :name %>
<%end%>
<%end%>
I think you are trying to do two different things here.
Select a list of Templates for which you want to create Installed Template joins to the Site.
From each selected Template create an instance of an Installed Template which links to the Site.
I think I would handle this through an accessor on the model.
On the Site Model (assuming standard rails naming conventions)
attr_accessor :template_ids
def template_ids
installed_templates.collect{|i_t| i_t.template.id}
end
def template_ids=(ids, *args)
ids.each{|i| i.installed_template.build(:site_id => self.id, :template_id => i) }
end
Then the form becomes pretty simple
<% form_for #site do |f| %>
<% f.collection_select :template_ids, Template.all, :id, :name, {}, :multiple => true %>
<% end %>
Is a join model necessary here?
class Site < ActiveRecord::Base
has_and_belongs_to_many :templates
end
In the form, easiest if using simple_form:
<%= form.input :template_ids, :as => :radio_buttons, :collection => Template.order(:name), :label => 'Templates installed:' %>
If the join model is necessary, then I would have a dropdown or list of templates I could add, each with a button that submits the form and adds that template. Then I'd use the update_only nested attributes form to display the currently installed templates with their settings.
class Site < ActiveRecord::Base
...
attr_accessor :install_template_id
before_validation :check_for_newly_installed_template
def check_for_newly_installed_template
if install_template_id.present?
template = Template.find install_template_id
if template.present? and not templates.include?(template)
self.templates << template
end
end
end
end
That works kind of like Drupal, where you have to enable the theme before you can edit its settings or select it as the current theme.

Use rails3-jquery-autocomplete with simple form on a has_and_belongs_to_many association

I'd like to have a form where groups can add their interests and this form should help them with autocompletion.
As this is a many-to-many relation, I don't understand how to implement it
class Group < ActiveRecord::Base
attr_accessible :description, :name, :project_id, :interests
before_save :get_next_available_name
has_many :users
belongs_to :project
has_and_belongs_to_many :interests
end
class Interest < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :groups
end
In the view I have:
<%= simple_form_for #group do |f| %>
<%= f.autocomplete_field :interests, autocomplete_interest_name_groups_path %>
<%= f.submit "Interesse eintragen" %>
<% end %>
Of course I entered "rails g autocomplete:install"
I probably have to edit the routes and added this to the routes.rb:
resources :groups do
get :autocomplete_interest_name, :on => :collection
end
UPDATE:
As Saurabh suggested, I put he "autocomplete :interest, :name" in the controller, not in the model.
But I have two problems now:
First: There is no autocomplete coming up.
Second: After adding 'ruby' Interest and submitting the form: In the input field there is written this:
[#<Interest id: 38, name: "ruby", created_at: "2013-02-28 09:25:53", updated_at: "2013-02-28 09:25:53">]
But of course the field itself should be empty.
If this gem is not compatible with Rails 3.2, someone should tell me...
Define the autocomplete in your controller and remove it from model as:
class GroupsController < ApplicationController
autocomplete :interest, :name
# ...
# ...
end
UPDATE:
According to your question update, this is what you need to do now:
Your view:
<%= simple_form_for #group do |f| %>
<%= f.autocomplete_field :interests, autocomplete_interest_name_groups_path %>
<%= f.submit "Interesse eintragen" %>
<% end %>
More from the rails3 jquery autocomplete sources.

Change content based on dropdown using Rails, Ajax and Jquery

I'm trying to display the recent scores of a team from a database based on the selection from a collection_select drop down. I know that I need to listen for the change event on the drop down but I don't know how to do the AJAX request or how to display the data in the view.
Ok, I will write a example with category and subcategory models.
The first is relation between models:
class Category
has_many :subcategories
has_many :objects
end
class Subcategory
belongs_to :category
has_many :objects
end
class Object
belongs_to :category
belongs_to :subcategory
end
Now the form on view, for example with simple_form gem (you can do it with form_for):
<%= simple_form_for(#object, :html => {:multipart => true }) do |f| %>
<%= f.input :category, :collection => Category.all :prompt => "Select Category" %>
<%= f.input :subcategory, :label_html => { :class => 'subcategory_label_class' } do %>
<%= f.grouped_collection_select :subcategory_id, Category.order_by(:title), :subcategories, :title, :id, :name, include_blank: true %>
<% end %>
<%= f.button :submit %>
<% end %>
With this we grouped the subcategories with their parent category.
The next step you must add the code to your objects.js.coffee
$('#object_subcategory_id').parent().hide()
subcategories = $('#object_subcategory_id').html()
$('#object_category').change ->
category = $('#object_category :selected').text()
escaped_category = category.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g, '\\$1')
options = $(subcategories).filter("optgroup[label='#{escaped_category}']").html()
if options
$('#object_subcategory_id').html(options)
$('.subcategory_label_class').show()
$('#object_subcategory_id').parent().show()
else
$('#object_subcategory_id').empty()
$('.subcategory_label_class').hide()
$('#object_subcategory_id').parent().hide()
You can adapt this example to your needs.
I hope it helps.
Regards!
you need to build a separate controller and send the ajax request when your change event is triggered, the controller sends back a js response, that you have to handle in your clients javascript... the following link should give you an example http://blog.bernatfarrero.com/jquery-and-rails-3-mini-tutorial/

Rails 3.2: multiple nested data from one model

How to create form and action for multiple nested attributes if:
LineItem:
has_many :item_options, :dependent => :destroy
has_many :product_options, :through => :item_options
ProductOption:
belongs_to :product
belongs_to :option
has_many :item_options
has_many :line_items, :through => :item_options
ItemOption:
attr_accessible :line_item_id, :product_option_id
belongs_to :line_item, :foreign_key => "line_item_id"
belongs_to :product_option,:foreign_key => "product_option_id"
When I'm creating new LineItem, I need to create new ItemOption(s). This is my form:
<%= form_for(LineItem.new) do |f| %>
<%= f.hidden_field :product_id, value: #product.id %>
<%= f.fields_for :item_options do |io| %>
<% #product.options.uniq.each do |o| %>
<%= o.name %>:
<%= io.collection_select :product_option_id, o.product_options.where(:product_id => #product.id), :id, :value %>
<% end %>
<%= f.submit %>
<% end %>
When I'm clicking on Add To Cart, I've get:
ItemOption(#70296453751440) expected, got Array(#70296430421140)
When Adding accepts_nested_attributes_for :item_options to LineItem, my selects not diplayed :(
With
<%= select_tag "product_option_id", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
#item_options not created:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
And last one, I've create action like this:
#line_item = LineItem.new(params[:line_item])
#line_item.item_options.build
....
Where am I wrong? :( I'm totally confused.
ps. similar question Rails 3.2 has_many through form submission
This is form:
Looks this line:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
The parameter product_option_id is outside line_item hash, and will be inside. Maybe you need write the select like this:
<%= select_tag "line_item[product_option_id]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
I'm not sure, but maybe is this. Maybe I need more information, like the exact line where is failing.
Extra, the :foreign_key => "line_item_id" and :foreign_key => "product_option_id" are not necesary, because, the belongs_to model name is the same and will use these foreign_key. From api.
Specify the foreign key used for the association. By default this is
guessed to be the name of the association with an “_id” suffix. So
a class that defines a **belongs_to :person** association will use
“person_id” as the default :foreign_key. Similarly, belongs_to
:favorite_person, :class_name => "Person" will use a foreign key of
“favorite_person_id”.
Edit
Sorry, the unknown attribute: product_option_id is because the attribute name is product_option_ids, and is an array, not a unique value. For a has_many relationship, the column name is collection_singular_ids, and the select should be:
<%= select_tag "line_item[product_option_ids][]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
This should work, I think :)...

Resources