semantic_field_for for arbitrary attribute - ruby-on-rails

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

Related

ActiveAdmin passing variable in controller

I have a permit and vehicle model. I am trying to update the AA create controller to work how I have it in my rails app. That is taking the vehicle license_number entered and inputting it into the permit table, then also taking the inputted permit_id and inputting it into the permits attribute of the vehicle it is related to in the vehicle table.
admin/permit.rb
permit_params :permit_id, :vehicle, :date_issued, :issued_by, :date_entered, :entered_by
form do |f|
f.inputs do
f.input :permit_id
f.input :vehicle, :collection => Vehicle.all.map{ |vehicle| [vehicle.license_number]}
f.input :date_issued, as: :date_picker
f.input :issued_by
end
f.actions
end
controller do
def new
#permit = Permit.new
#vehicle = #permit.build_vehicle
#vehicle = Vehicle.all
super
end
def create
vehicle = Vehicle.find_by(license_number: permit_params[:vehicle_attributes][:license_number])
#permit = current_user.permit.build(permit_params.merge(date_entered: Date.today,
entered_by: current_user_admin.email))
super
end
end
My errors that I am getting, is that it is inputting the license_number in for the permit_id and then it is also saying the permit_params is not a defined variable. Any help would be great, thanks!
You have an interesting case here: it is confusing because you have a model called Permit, and usually in Rails you name the params method something like permit_params. Turns out, permit_params is the general method signature for ActiveRecord to implement strong params: https://activeadmin.info/2-resource-customization.html
With that, instead of calling permit_params in your create action, you need to call permitted_params[:vehicle_attributes][:license_number]. That’s why it’s considering permit_params as an undefined variable. Again, those two method signatures will be the same for all your ActiveAdmin forms.
Additionally, I’m not sure if this is a typo but you define #vehicle twice in your new method. I’m not sure you need to build a vehicle for the permit form unless you’re doing nested forms. Either way, I think the last line should read #vehicles = Vehicle.all Then you can use that in your form, which also could use an update in the collection part of your form field:
form do |f|
f.inputs do
f.input :permit_id
f.input :vehicle, collection: #vehicles.map { |vehicle| [vehicle.license_number, vehicle.id] }
f.input :date_issued, as: :date_picker
f.input :issued_by
end
f.actions
end
The collection_select form tag will take the first item in the array as the value that appears in the form, and the second value will be the value passed through in the params (https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select).
Then in your create action, you can find the Vehicle with the id:
Vehicle.find(permitted_params[:vehicle_attributes][:vehicle_id])
I would avoid Permit as a model name, try using VehiclePermit.

How do I generate a bunch of checkboxes from a collection?

I have two models User and Category that have a HABTM association.
I would like to generate checkboxes from a collection of Category items on my view, and have them associated with the current_user.
How do I do that?
Thanks.
P.S. I know that I can do the equivalent for a dropdown menu with options_from_collection_for_select. I also know that Rails has a checkbox_tag helper. But not quite sure how to do both of them. I know I can just do it manually with an each loop or something, but am wondering if there is something native to Rails 3 that I am missing.
Did you check out formtastic or simple_form
They have helpers to write your forms more easily, also to handle simple associations.
E.g. in simple_form you can just write
= simple_form_for #user do
= f.association :categories, :as => :check_boxes
In form_tastic you would write
= simple_form_for #user do
= f.input :categories, :as => :check_boxes
Hope this helps.
You can use a collection_select and feed it the options. Assuming you have a form builder wrapped around a user instance, you can do something like this:
form_for current_user do |f|
f.collection_select(
:category_ids, # the param key, so params[:user][:category_ids]
f.object.categories, # the collection of items in the list
:id, # option value
:name # option string
)
end
You may want to pass the :multiple => true option on the end if needed.

Ruby on rails, split a big form into separate smaller forms

Could not find the answer to the question on how to split forms in rails in multiple smaller forms.
Say you have a big form with
firstname
lastname
gender
age
email
country
city
state
I have a validate_presence for all these fields. So when I create several forms like:
= simple_form_for #profile, :wrapper => :inline do |f|
= f.label "firstname"
= f.select :firstname
without all the values from the top list (first name,last name,etc) I get errors because the splitter form does not contain those values and they need to be present at first to make this work at all.
What would be a good way to have several forms but with only a portion of the values and update them without getting the issue described above?
If you want the ability to update pieces of the model then you need to split the validations into pieces as well.
One way to do it is to have a virtual attribute in your model that gets set by a hidden field in each form. E.g you may have a form:
= simple_form_for #profile, :wrapper => :inline do |f|
= f.hidden :form, :input_html => {:value => 'names'}
= f.label "firstname"
= f.select :firstname
Then in your model:
class Profile
attr_accessor :form
validates :firstname, :presence => true, :if => lambda { |o| o.form == "names" }
end
The validation will run only if the change was submitted from the right form.
Check out conditional validation guide: http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation for more details.
Other way is a multistep form as suggested by apneadiving: http://railscasts.com/episodes/217-multistep-forms This uses the same technique as in the first example by having a current_step attribute, but the progression is linear.
You're asking for a multi step form I guess.
Look at this screencast, you'll find conditional validations which are the way to proceed.

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

Accessing objects in semantic_fieds_for loop / formtastic

Model has accepts_nested_attributes_for for the relation and the form is as follows:
= semantic_form_for #obj, :url => path do |f|
= f.inputs do
= f.input :name
= f.semantic_fields_for :photos do |p|
= p.inputs :desc
= f.buttons
The form works well and everything is fine. However, I would like to display each photo near the field, so the user could se which picture she is going to annotate. Is there anyway, to access photo.id inside the fields_for loop?
Edit:
Is there any way to alter the order in which photos fields will be rendered in this example. As far as I can tell till now, that order is pretty random.
Well this was easy enough, the object is accesible by:
p.object
:-)
Second part of the question is solved with:
default_scope order(...)

Resources