Rails Simple Form Gem not setting association id - ruby-on-rails

I'm trying to use the simple form gem to populate a select box using an association. I have two associated models: job_category and job_type.
job_category has_many job_types
and
job_type belongs to job_category.
I'm successfully populating the select box using this form,
= simple_form_for(#job_type) do |f|
= f.error_notification
.form-inputs
= f.input :name
= f.association :job_category, :include_blank => false, :label_method => :name
.form-actions
= f.button :submit
and it is creating a job_type object when I hit my create route, but the job_category_id field in job_type isn't being set.
When I go to the command line instead, I am able to successfully create a new job using
JobType.create(name: "Test", job_category_id: 1)
Inspecting the post using the Chrome developer tools shows job_category_id being sent over as part of the post, so I don't have any idea why this isn't working.

If you are using Rails 4, can you confirm that you've added :job_category_id to your job_type_params method in JobTypesController?
If you have not, make sure :job_category_id is in your job_type_params method.
If you're using < Rails 4, add :job_category_id to your attr_accessible.

Related

Cocoon how to remove associations

I am trying to use the Cocoon gem to add/remove assets on asset_profiles. Everything up to this point works, I am just having a problem with link_to_remove_association. When the button is clicked, the field is removed. But if the field had been filled in and saved previously, I am unable to remove said association. The button just hides the field until I hit update. Is there a way to actually remove the association from the database through link_to_remove_association? Any help is much appreciated. Thanks in advance.
Here is the code I am referring to:
Asset.show
= simple_form_for([#asset_profile, #asset]) do |f|
= f.input :max_users, as: :hidden
#assets_users
= f.simple_fields_for :assets_users do |assets_user|
= render "assets_user_fields", f: assets_user
.links
= link_to_add_association "Add Another User", f, :assets_users
= f.submit
Asset._assets_users_fields
.nested-fields
= f.input :user_id, collection: #users.order(:last_name), :label => "User"
= link_to_remove_association "Remove", f
Screenshot of page pre-remove:
Screenshot of post-remove:
Screenshot of post-update(page reload):
I would much rather, after the update, the page be reloaded and looking like below, which is the form for initially adding users to an asset:
When using strong parameters, you have to make sure to permit :id and :_destroy, as documented by the way (see documentation ).
It is not unlogical: cocoon sets the _destroy if something needs to be removed, rails then needs the id to know what to remove.
Im my case, i forget for allow_destroy: true.
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Did you permit the nested parameter _destroy in either permit (strong_parameters) or attr_acceptible?
Your asset_profile_params should look like
def asset_profile_params
params.require(:asset_profile).permit(:max_users, :asset_users_attributes => {:user_id, :_destroy})
end

AssociationTypeMismatch with Rails form using Simple_form

Hello everyone: I'm trying to solve a problem with my form.
I have a product model where every product has one brand.
I'm using simple_form to create/update my products. In my original version I use
= simple_form_for [:admin, product] do |form|
...
= form.association :brand
...
Now I add a jquery select with ajax data loading and I change my input to:
= form.input_field :brand, input_html: { class: 'form-control select2' }
When I save my form I have an error:
ActiveRecord::AssociationTypeMismatch in Admin::ProductsController#create
Brand(#70355202593700) expected, got String(#70355134114860)
In my post params 'brand' is now a string equivalent to the ID of the brand I associate to my product, and I don't know how to fix the association.
Any hint?
For your input_field, it would probably need to be :brand_id because it's no longer being built as an association (that only works with the .association method).
If you are on Rails 3, be sure :brand_id is added to your model's attr_accessible expression.

How to have a drop down <select> field in a rails form?

I am creating a scaffold -
rails g scaffold Contact email:string email_provider:string
but I want the email provider to be a drop down (with gmail/yahoo/msn as options) and not a text field. How can I do this ?
You can take a look at the Rails documentation . Anyways , in your form :
<%= f.collection_select :provider_id, Provider.order(:name),:id,:name, include_blank: true %>
As you can guess , you should predefine email-providers in another model -Provider , to have where to select them from .
Or for custom options
<%= f.select :desired_attribute, ['option1', 'option2']%>
You create the collection in the Contact controller -
app/controllers/contacts_controller.erb
Adding
#providers = Provider.all.by_name
to the new, create and edit methods, using a scope for the by_name in the Provider model - app/models/provider.rb - for the ordering by name
scope by_name order(:name)
Then in the view - app/views/contacts/_form.html.erb - you use
<%= f.collection_select :provider_id, #providers, :id, :name, include_blank: true %>
For rails forms, I also strongly recommend you look at a form builder like simple_form - https://github.com/plataformatec/simple_form - which will do all the heavy lifting.
This is a long way round, but if you have not yet implemented then you can originally create your models this way. The method below describes altering an existing database.
1) Create a new model for the email providers:
$ rails g model provider name
2) This will create your model with a name string and timestamps. It also creates the migration which we need to add to the schema with:
$ rake db:migrate
3) Add a migration to add the providers ID into the Contact:
$ rails g migration AddProviderRefToContacts provider:references
4) Go over the migration file to check it look OK, and migrate that too:
$ rake db:migrate
5) Okay, now we have a provider_id, we no longer need the original email_provider string:
$ rails g migration RemoveEmailProviderFromContacts
6) Inside the migration file, add the change which will look something like:
class RemoveEmailProviderFromContacts < ActiveRecord::Migration
def change
remove_column :contacts, :email_provider
end
end
7) Once that is done, migrate the change:
$ rake db:migrate
8) Let's take this moment to update our models:
Contact: belongs_to :provider
Provider: has_many :contacts
9) Then, we set up the drop down logic in the _form.html.erb partial in the views:
<div class="field">
<%= f.label :provider %><br>
<%= f.collection_select :provider_id, Provider.all, :id, :name %>
</div>
10) Finally, we need to add the provders themselves. One way top do that would be to use the seed file:
Provider.destroy_all
gmail = Provider.create!(name: "gmail")
yahoo = Provider.create!(name: "yahoo")
msn = Provider.create!(name: "msn")
$ rake db:seed
<%= f.select :email_provider, ["gmail","yahoo","msn"]%>
Please have a look here
Either you can use rails tag Or use plain HTML tags
Rails tag
<%= select("Contact", "email_provider", Contact::PROVIDERS, {:include_blank => true}) %>
*above line of code would become HTML code(HTML Tag), find it below *
HTML tag
<select name="Contact[email_provider]">
<option></option>
<option>yahoo</option>
<option>gmail</option>
<option>msn</option>
</select>
Rails drop down using has_many association for article and category:
has_many :articles
belongs_to :category
<%= form.select :category_id,Category.all.pluck(:name,:id),{prompt:'select'},{class: "form-control"}%>
In your model,
class Contact
self.email_providers = %w[Gmail Yahoo MSN]
validates :email_provider, :inclusion => email_providers
end
In your form,
<%= f.select :email_provider,
options_for_select(Contact.email_providers, #contact.email_provider) %>
the second arg of the options_for_select will have any current email_provider selected.
I wanted to display one thing (human readable) but store another (an integer id).
Small example
Here's a small example that helped:
<%= form.select(:attribute_name, {cat: 5, dog: 3} )%>
The {cat: 5, dog: 3} will display "cat" and "dog", but save 5 and 3.
Real world example
Here's the actual use case. It displays the names of sellers (that humans can read), but saves the sellers' id (an integer):
<div class="field">
<%= form.label :seller_id %>
<%= form.select :seller_id, seller_names_and_ids(), {include_blank: true}, {required: true, class: "form-control"} %>
</div>
And the helper is defined as:
def seller_names_and_ids
# We want this to produce a hash of keys (the thing to display) and values (the thing to save,
# in thise case the seller_id integer)
sellers = Seller.all
h = {}
sellers.each do |seller|
thing_to_display = seller.name + " (" + seller.id.to_s + ")"
thing_to_save_in_db = seller.id
h.store(thing_to_display, thing_to_save_in_db)
end
h
end

Selecting a default picture with radio button in a new nested attributes form

I've got a Rails project which has a car model and it has multiple pictures. I've created a nested form so I can input the cars details and pictures all at the same time. I would like a radio button to select the picture to display in the gallery.
%table
= simple_form_for [#car] :html => {:multipart => true} do |f|
= f.error_messages
= f.input :make
= f.input :model
= f.input :engine
= f.input :price
= f.simple_fields_for :car_pictures do |builder|
.picture
= builder.input :caption
= builder.input :picture
.thumb= image_tag builder.object.picture(:thumb)
= f.button :submit
Is it possible to use a radio button in the 'fields_for' section to select the default/main picture? Or is there a better way?
Update
By putting the following under the fields_for all the radio buttons work independently, which is not what I want.
= builder.radio_button(:favourite, "test")
Each radio button is getting a unique name.
Update
What if I used the object_id as the value, how would I go about linking this in the create method?
= f.radio_button(:favourite_pic, builder.object_id)
Yes, your last guess was correct. I made a test application in which the customer can select a favorite photo: https://github.com/eicca/attrs_test (see commit changes marked by "added favorite example").
There are two main points (according to your situation):
= f.radio_button(:favorite_pic_id, builder.object.id)
and
#models/car
has_one :favorite_pic, :class_name => "CarPicture"
And you need to add favorite_pic_id field to your cars table.
Why not? :) Only selected radio button will be sent to the server. So, only thing you've got to do - is to give it proper name/value and make sure that you have an accessor for it to support mass-assignment.

an example of a nested form in simple form?

I am still struggling both writing the controller and the actual form to be able to nest one form in another with an optional model?
I have Message which has many contacts
When submitting a message, I want to add a contact optionally.
I have this as an example:
= simple_form_for Message.new, :remote => true do |f|
#message_form
= f.error_messages
%p
= f.input :account_name, :url => autocomplete_account_name_messages_path, :size => 40, :as => :autocomplete
%p
= f.input :topic, :required => true,
:input_html => {:size => 30}
#add_contact_btn
= link_to "Add Contact"
#contact_form
= f.simple_fields_for :contactd do |fc|
= fc.input :email
= fc.input :first_name
= fc.input :last_name
= f.submit 'Give'
= f.submit 'Request'
For Message.rb model, I have the following:
has_many :contacts
accepts_nested_attributes_for :contacts, :reject_if =>:all_blank
Note: When I used :contacts in the simple_fields_for it didn't work, so it is singular. But the reverse for accepts_nested_attributess_for.
In my create controller for message, I included message.contacts.build
But right now I am still generating nil contacts.
Here is what I see passed as form data from google chrome:
message%5Baccount_name%5D:McKesson
message%5Btopic%5D:testing a contact
message%5Bbody%5D:testing this
sender_id:
receiver_id:23
message%5Bcontacts%5D%5Bemail%5D:888#gmail.com
message%5Bcontacts%5D%5Bfirst_name%5D:Ang
message%5Bcontacts%5D%5Blast_name%5D:Name
The correct method name is simple_fields_for (notice the plural)
Also, you need to keep the f. to call it on the simple_form object
I have a small project where I demonstrate how to use nested forms in simple-form, combined with cocoon (a gem I created to add/remove nested elements dynamically).
The project is on github.
Hope this helps.
In my create controller for message, I included message.contacts.build
But right now I am still generating nil contacts.
Make sure you put in your Message.rb model the ability for it to accept the attributes too.
class Message < ActiveRecord::Base
attr_accessible :contacts_attributes
has_many :contacts
accepts_nested_attributes_for :contacts
I know it doesn't answer your question fully but it may have just been this. When it comes to my project, it would return nil if i didn't include the :contacts_attributes, in my case it deals with products. Hope this helps even if I'm not using simple form as of now!
I faced similar issues working with nested forms. As suggested by JustinRoR you need to define
attr_accessible: contacts_attributes.
You should be able to test the hash in the ruby console ( I am not sure if you have tried this). I suggest you to print the params[:message] and use this to create message from console like Message.new(params[:message]). (Note params[:message] is what you get by printing the params[:message] hash).
Once it works in console it should work like charm

Resources