rails - grouped_collection_select with 3 tables - ruby-on-rails

The Rails docs example for grouped_collection_select is set up similar to what I need but I want to use 2 selects. The first one will list the continents. Then, based on the continent selection, I want to show a list of cities.
class Continent < ActiveRecord::Base
has_many :countries
# attribs: id, name
end
class Country < ActiveRecord::Base
belongs_to :continent
# attribs: id, name, continent_id
end
class City < ActiveRecord::Base
belongs_to :country
# attribs: id, name, country_id
end
I know the first select would be written as:
<%= f.collection_select :continent_id, Continent.order(:name), :id, :name %>
The second one is giving me problems:
<%= f.grouped_collection_select :city_id, Continent.order(:name), :countries, :name, :id, :name %>
The need for the country table is throwing me off. Any suggestions?

Related

Can't access field through 3 models in Rails 5

I'm trying to do something very similar to this question
I have 4 models, one of which (CoffeeBlend) is a join table:
class CoffeeRoast < ApplicationRecord
has_many :coffee_blends
has_many :coffee_beans, through: :coffee_blends
has_one :country, through: :coffee_beans
end
class CoffeeBean < ApplicationRecord
has_many :coffee_blends
has_many :coffee_roasts, through: :coffee_blends
belongs_to :country
end
class Country < ApplicationRecord
has_many :coffee_beans
end
class CoffeeBlend < ApplicationRecord
belongs_to :coffee_bean
belongs_to :coffee_roast
end
My coffee_beans table has a column called country_id which is populated with the id from the countries table.
In my coffee_roasts_show I want to be able to pull the associated country of the coffee bean. My latest attempt looks like
<% #coffee_roast.coffee_beans.country.country_name %>
which gives undefined method 'country'
Or
<% #coffee_roast.coffee_beans.countries.country_name %>
returns undefined method 'countries'
Do I have my associations correct? Is my show code wrong?
The method #coffee_roast.coffee_beans returns you association, not a single record. That's why you cannot call #country on that. If you need all the countries, you can use #map:
<% #coffee_roast.coffee_beans.map {|cb| cb.country.country_name } %>
Edit:
If you want to show the list in the browser, add = to your ERB mark:
<%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name } %>
It may also be useful to explicitly convert contry names to a string with Array#join
<%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name }.join(', ') %>

Active Record Association Type Mismatch

I have nested results upon matches like this
/matches/16/results/13/edit
Where I have the following select field, this shows the correct information ( team.name and its team.id)
<%= f.collection_select :winner, #select_winner_loser, :id, :name %>
Now when I try to edit my result and selecting a winner I get this:
ActiveRecord::AssociationTypeMismatch Team(#10504340) expected, got String(#6163240)
"Raised when an object assigned to an association has an incorrect type." http://api.rubyonrails.org/classes/ActiveRecord/AssociationTypeMismatch.html
Winner is a team object, result.rb looks like this
class Result < ActiveRecord::Base
has_one :match
belongs_to :winner, class_name: "Team"
belongs_to :loser, class_name: "Team"
end
#select_winner_loser comes from my results_controller
def edit
#select_winner_loser = []
#select_winner_loser << #match.top
#select_winner_loser << #match.bottom
end
Match.top & bottom is also team objects
class Match < ActiveRecord::Base
belongs_to :top, class_name: "Team"
belongs_to :bottom, class_name: "Team"
...
belongs_to :result
end
I dont see why I would get this since I have the correct objects in my select field, any ideas?
Thanks
Change
<%= f.collection_select :winner, #select_winner_loser, :id, :name %>
to
<%= f.collection_select :winner_id, #select_winner_loser, :id, :name %>
and your permitted parameters accordingly. Rails will create a Team object when it sees the _id in the name.

Creating a form with nested attributes and prompt (has_many association)

So the issue is i have these classes.
class Post < ActiveRecord::Base
belongs_to :category
has_many :text_fields
has_many :integer_fields
accepts_nested_attributes_for :text_fields
accepts_nested_attributes_for :integer_fields
end
class Category < ActiveRecord::Base
has_many :fields
end
class TextField < ActiveRecord::Base
belongs_to :post
end
class IntegerField < ActiveRecord::Base
belongs_to :post
end
Category has many Fields, every field (not to confuse with TextField or IntegerField) has a column "type" (to specify if it is Text or Integer field) and description (eg. "how many pets do you have" for integerField). When User want to create a new post, first he chooses category. then, based on what Fields each category has, proper TextFields and IntegerFields should be build and rendered.
I hope my point is clear, i want to have Post generator which generate different fields based on category, simple as that.
Post form (without steps for now)
= simple_form_for #poster do |f|
= f.input :category_id, collection: Category.all, prompt: "Choose category"
= f.input :title
= f.simple_fields_for :text_fields do |ftf|
= ftf.input :description
= f.simple_fields_for :integer_fields do |fif|
= fif.input :integer_number
= f.submit
And heres whats wrong. i dont know how to give each field a proper prompt. each TextField or IntegerField is there just because Category requires it (based on fields). But can i make it has a proper prompt, not just 'integer number' every time?
Here's how i build those fields, its open for changes:
def build_fields_based_on_category
category.fields.each do |field|
self.send("#{field.kind}_fields").build
##### 'kind' can be integer or 'text'
end
end

Rails Format Collection_Select Based on two relationships

I'm trying to figure out how to construct a collection_select to include two relationships. Here are my models:
class Country < ActiveRecord::Base
has_many :companies, :dependent => :destroy
end
class Company < ActiveRecord::Base
belongs_to :country
has_many :departments, :dependent => :destroy
end
class Department < ActiveRecord::Base
belongs_to :company
end
When I create a new company I use the following to show a select box based on the relationship.
<%= collection_select(:company, :country_id, Countries.all, :id, :name, :prompt => 'Please select country') %>
But for the departments I'd like to have a select which let's the user select it's company from a select which also includes the companies country, formatted in the following way:
Company 1 - Country 1
Company 2 - Country 1
If i use the following I will only get a list of all the companies which I'd like to be able to see from the list which country they are from.
<%= collection_select(:device, :cabinet_id, Cabinet.all, :id, :name, :prompt => 'Please select cabinet') %>
Is there a way for rails to pull the information for the country into a select and append the entry with it's parent country?
I hope I've worded this question correctly! Sorry if it isn't clear.
Even if #jvnil solution works, I think you should avoid putting this logic in your view.
Instead, you could create an instance method in your Company model and use it in your select.
In your model :
class Company< ActiveRecord::Base
def name_for_select
name + " - " + country.name
end
end
And in your view :
<%= collection_select(:department, :company_id, Company.all, :id, :name_for_select %>
Use
UPDATE: move logic code to model
# company.rb
def company_with_country
"#{name} - #{country.name}" # this is better than using `string + string` since it creates only 1 string
end
# view
collection_select :department, :company_id, Company.includes(:country).all, :id, :company_with_country
UPDATE: faster version because it only uses needed columns
# controller
#companies = Company.joins(:country)
.select('companies.id, companies.name, countries.name AS country_name')
.map { |c| ["#{c.name} - #{c.country_name}", c.id] }`
# view
select :department, :company_id, #companies

Problems Using collection_select to store value in the database

I have two models:
Project.rb
class Project < ActiveRecord::Base
belongs_to :customer
end
and Customer.rb
class Customer < ActiveRecord::Base
has_many :projects
end
Inside the _form.html.erb I have:
<p>
<label>Select Customer</label>
<%= f.collection_select :customer_id, Customer.all, :id, :name, :include_blank => true %>
</p>
Which should Collect the Customers from the Customer model and display all the customers, finally it should assign the value to the customer_id which is in projects table.
Rite now the everything is passing when i check the log. When I select the first customer with value=1, it passes customer_id = "1" in my log but it doesn't get stored in the table. It shows customer_id = nil in the projects table.
Can someone help. Thanks :)
Do check that you added customer_id in attr_accessible method like,
class Project
attr_accessible :your_other_attributes, :customer_id
end

Resources