Rails f.select Save Id an Name at the same time - ruby-on-rails

I have a form with the f.select option. I want to add the Company ID and the Company Name when the company name is selected from the options. Is it possible to add multiple attributes in the f.select line of code? This is how my code looks:
<div class="field">
<%= f.label 'Client' %>
<%= f.select :client_id, Client.all.collect { |c| [ c.companyName, c.id ] } %>
I want to also assign the companyName to my :companyName attribute, but the id is the only thing that is being saved right now.
Thanks.

I think you can use associations for this. You should have 2 models as below.
class Company < ApplicationRecord
has_many :clients
end
class Client < ApplicationRecord
belongs_to :company
end
Your should use variable instead in views for rendering all clients list with this
<%= f.select :client_id, #clients.collect { |client| [ client.name, client.id] } %>
Controller:
#clients = Client.all
On Submit the client_id will be passed to controller. You can then find the company associated with the client and other logic.
client = Client.find(params[:client_id])
company = client.company
# etc ..

In the controller action where your form submits you can write before saving or updating record.
params[:your_object][:companyName]=Client.find_by(id: params[:your_object][:client_id]).companyName
Remember to a add params[:your_object][:companyName] to your strong params. e.g.
params.require(:your_object).permit(:client_id, ... , :companyName)
Before anything be sure your client_id is in same object and permitted and apply same to companyName attribute
Hope This Helps

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?

select_check_boxes with an has many through relation and :checked option

I am using collection_check_boxes to create object in a has_many through relation;
here some models:
#emotion.rb
class Emotion < ActiveRecord::Base
has_many :emotional_states
has_many :reports, :through => :emotional_states
end
#report.rb
class Report < ActiveRecord::Base
has_many :emotional_states
has_many :emotions, :through => :emotional_states
[... other "irrelevant" stuff here ...]
end
#emotional_states.rb
class EmotionalState < ActiveRecord::Base
belongs_to :report
belongs_to :emotion
end
As you may understand when I create a Report I also select with a collection_check_box a list of Emotions I want to bind to that report (through the model EmotionalState); Everything works on create (I retrieve the hash values and if #report.save I also create EmotionalStates with the #report.id and #emotion.id.)
But when it cames to edit the Report I would like to edit also the associated EmotionalStates (this means creating new EmotionalStates or deleting old one).
How can I populate the select_check_boxes with ALL the available Emotions having checked that emotions that are alredy associated through the EmotionalStates bojects?
If I write something like:
<%= collection_check_boxes(:report, :emotion_id, #report.emotional_states.map{|e| e.emotion}, :id, :name) %>
I'll get a unchecked checkbox for every alredy associated Emotion.
<%= collection_check_boxes(:report, :emotion_id, Emotion.all, :id, :name, :checked => #report.emotional_states.map{|e| e.emotion}) %>
While this code will correctly returns Emotion.all, but will not check the emotions alredy associated to #report through #report.emotional_states.
I've searched all around the wheb for examples on the usage of :checked options for collection_select_boxes without any results...
any hint?
I did the same once in this way.you can also try :
Emotions:
<% Emotion.all.each do |emotion| %>
<%= check_box_tag 'report[emotion_ids][]' , emotion.id, #report.emotion.include?(emotion) %><%= emotion.name %><br/>
<% end %>
In Controller add :emotion_ids=>[] into strong parameters.
And one line into controller update method:
params[:report][:emotion_ids] ||= []
After coming back to this bug I discovered that the problem was an incorrect use of the .map method, mapping a whole object (e.emotion) instead its id (e.emotion.id).
This easily fixed my problem:
<%= collection_check_boxes(:report, :emotion_id, Emotion.all, :id, :name, :checked => #report.emotional_states.map{|e| e.emotion.id}) %>
Thank you for your help!

RecordNotFound with accepts_nested_attributes_for and belongs_to

I get
ActiveRecord::RecordNotFound: Couldn't find Client with ID=3 for Order with ID=
when trying to submit an Order form for an existing client. This happens through the form or the console by typing:
Order.new(:client_attributes => { :id => 3 })
payment_form.html.erb:
<%= semantic_form_for #order, :url => checkout_purchase_url(:secure => true) do |f| %>
<%= f.inputs "Personal Information" do %>
<%= f.semantic_fields_for :client do |ff| %>
<%= ff.input :first_name %>
<%= ff.input :last_name %>
<!-- looks like semantic_fields_for auto-inserts a hidden field for client ID -->
<% end %>
<% end %>
<% end %>
Order.rb:
class Order < ActiveRecord::Base
belongs_to :client
accepts_nested_attributes_for :client, :reject_if => :check_client
def check_client(client_attr)
if _client = Client.find(client_attr['id'])
self.client = _client
return true
else
return false
end
end
end
The reject_if idea came from here but I logged the method and it's not even being called! It doesn't matter what its name is!
Note: Feb 2020
Since I'm starting to get downvotes on this 8 years later, adding this note. While this was the original solution I went with 8 years ago, a better one has been proposed by MatayoshiMariano (5 years after my OP).
My Original Fix
Fixed the issue by overloading the client_attributes= method, as described here:
def client_attributes=(client_attrs)
self.client = Client.find_or_initialize_by_id(client_attrs.delete(:id))
self.client.attributes = client_attrs
end
If you only want a new Order with an existing client, without modifying the client, you need to assign the id.
Order.new(client_id: 3)
This is another way to do this without overloading the client_attributes= method and cleanest
The new Order now has the client with ID 3
If you also want to update ant client's attributes you must add the client_attributes, for example:
Order.new(client_id: 3, client_attributes: { id: 3, last_order_at: Time.current })
See https://github.com/rails/rails/issues/7256 from 2012.
If you have has_many relationship, this will work. Tested on Rails 6.0.2
def clients_attributes =(attributes)
# Get IDs for any clients that already exist.
client_ids = attributes.values.map { |a| a[:id] }.compact
# Now find them all and move them to this section.
clients << Client.find(client_ids)
# Update them with standard `accepts_nested_attributes_for` behaviour.
super attributes
end
Had the same error creating a new Thing for existing model with has_many and belongs_to relations.
Fixed it by adding a hidden field for the id of the existing model, for instance User, to the form.
= form.input :user_id, as: :hidden
Then new Thing was created without the error.

Search by association in Rails 3 with MetaSearch

I'm using MetaSearch gem in my Rails 3 project.
I have two models:
class Company < ActiveRecord::Base
belongs_to :city
end
class City < ActiveRecord::Base
has_many :companies
end
I have the action in CompaniesController:
def index
#search = Company.search(params[:search])
#companies = #search.all
end
The action's view contains:
= form_for #search do |f|
= f.label :city_id_equals
= f.select :city_id_equals
= f.submit 'Search'
I want a list with city names to be rendered and the opportunity to search the companies by city. But instead of the names and ids of the cities I have something like "City:0x00000102a20488" and the search doesn't work properly.
I think that the mistake is here: ":city_id_equals". How to make it correct?
The solution is found!
Instead of:
= f.label :city_id_equals
= f.select :city_id_equals
I should use:
= f.label :city_id_equals
= f.collection_select :city_id_equals, City.all, :id, :name, :include_blank => true
Not sure your question is really clear.
First of all, I'm guessing you have something like <City:0x00000102a20488>, which is the string representation of a ruby object. If you want to display the name of the city, city.name should make the trick (assuming you have a name member on the city!).
For the search, I don't really get what you are trying to do. What is :city_id_equals supposed to mean to you?

declarative_authorization problem with creating new user

I used declarative_authorization for my app and had problem with creating new user.
my User model code:
class User < ActiveRecord::Base
ROLE_TYPES = ["admin", "user", "guest"]
validates_inclusion_of :roles, :in => ROLE_TYPES
def role_symbols
#role_symbols ||= (roles || []).map{|r| r.to_sym}
end
my view code:
<% form_for(#user) do |f| %>
...
<p>
<%= f.label :roles %><br />
<%= f.select :roles, User::ROLE_TYPES, :prompt => "Select a role" %>
</p>
<%= f.submit 'Add User' %>
<% end %>
every time i tried to create a new user and select the role from the drop-down list, the view complaint:
Roles is not included in the list
from the output of the script/server, i can see the roles was actually set:
"user"=>{"name"=>"kc", "password_confirmation"=>"kc", "roles"=>"guest", "password"=>"kc", "email"=>"kc#one.com"}
can anyone tell me what's wrong? why the validation wont' pass?
Is it possible that you've got attr_accessible attributes on the user to prevent mass assignment of certain attributes and that :roles isn't in there? You would get a warning about this in your logs though. The default User class generated by restful_authentication does include the attr_accessible call so it may be there without you having added it if you are using that authentication plugin too.
Is there definitely a roles attribute of the right type for users? It looks like you're expecting roles to be a single string from your form but in the code from declarative_authorization you've got (roles || []).map which suggests that that part of the code at least is expecting an array of roles.

Resources