Rails using join table to display grouped_collection_select - ruby-on-rails

I'm trying to setup a Rails 4 form to display all of the different store branches in a collection_select, followed by a grouped_collection_select displaying all of the possible combinations of storage types for each branch. I then want to filter out the storage types not available at a certain branch using CoffeeScript, as shown in Railscasts #88 (this is not an issue)
However, I can't figure out how to populate the grouped select pre-filtering. I need to go through the joining table StorageTypeBranch to find the storage types available at each branch.
My models:
class StorageType < ActiveRecord::Base
has_many :storage_type_branches
has_many :branches, through: :storage_type_branches
end
class Branch < ActiveRecord::Base
has_many :storage_type_branches
has_many :storage_types, through: :storage_type_branches
end
# Joining table
class StorageTypeBranch < ActiveRecord::Base
belongs_to :storage_type
belongs_to :branch
end
Controller:
def new
#branches = Branch.where(is_active: true).order(:name)
# Doesn't work because it has to be called on one instance of the model.
# What should this be?
#storage_types = #branches.storage_types.all
end
View:
<%= f.label :branch_id %>
<%= f.collection_select :branch_id, #branches, :id, :name, prompt: '<--- Select a Branch --->' %>
<br/>
<%= f.label :storage_type_id %>
# Where I want the grouped select to be
<%= f.grouped_collection_select #storage_types %>
The end result I'm looking to achieve:
Any help would really be appreciated.

If you want all branch types for the list of branches:
#storage_types = #branches.flat_map{|branch| branch.storage_types}.uniq # Array
If you want them for each branch:
#storage_types = Hash[#branches.map{|branch| [branch, branch.storage_types]}]
# {branch1 => [storage_typeA, storage_typeB], branch2 => [storage_typeC, storageTypeE]}
You can then group the collection with something like:
<%= f.input :storage_types, :as => :grouped_select, :collection => #storage_types, :group_method => :first, :group_label_method => :last %>
For more alternative see: simple_form: how to create a grouped select box?

Related

How can I synchronize a has_many association using accepts_nested_attributes_for by foreign_key instead of ID?

I would like to synchronize a has_many association by foreign key. It seems I have to write custom code to do this. Is there any Rails / Active Record magic / Gem to achieve this? Specifically, I'd like to synchronize a join-table where the pairs of foreign keys should be unique.
class Food < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of => :food
accepts_nested_attributes_for :food_tags, :allow_destroy => true
end
class FoodTag < ActiveRecord::Base
belongs_to :tag, :inverse_of=>:food_tags
belongs_to :food, :inverse_of=>:food_tags
end
class Tag < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of=>:tag
has_many :foods, :through=>:food_tags
end
For my form with nested attributes (or my JSON API), I'd really like to omit the FoodTag id and use the tag_id to synchronize when updating a food.
I want to submit this on update to show that the tag is set or cleared
# this one is set
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
Instead, I have to submit this for update:
# this one is set
food[food_tag_attributes][0][id] = 109293
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][0][id] = 109294
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
This pushes a burden to the client to know the IDs of the food tag records instead of just being able to Set or Clear tags based on the tag id.
Can this be done easily? I'm sure I could write a before_save filter on Food, but it seems like there should be a reasonably generic solution.
There is an option called index: for fields_for in the view helper. You can set the index as your foreign_key. Then instead of sequential or some arbitrary numbers, your foreign_key will be used as the key to refer to your object.
EDIT:
<%= form_for #person do |person_form| %>
<%= person_form.text_field :name %>
<% #person.addresses.each do |address| %>
<%= person_form.fields_for address, **index**: address.id do |address_form|%>
<%= address_form.text_field :city %>
<% end %>
<% end %>
<% end %>

How to display associated model's attribute in Active Admin index with belongs_to/has_many relationship (Rails 3.2/Active Admin)

I'm building a daily deal Rails app to learn RoR.
I am facing a problem for the past few hours : i can't get a model's attribute of an other associated model on active admin. Let me show you exactly the problem :
I have two models: Brand (i.e the brand of the deal) and Deal. A deal belongs to a Brand but a Brand can have many Deals.
models/deal.rb is like this:
class Deal < ActiveRecord::Base
belongs_to :brand
and we have models/brand.rb:
class Brand < ActiveRecord::Base
has_many :deals
attr_accessible :name
And i did the t.belongs_to in my migrations so this is ok.
In Active Admin's Deals' create form , i type, as admin, which brand the deal is associated with:
admin/game.rb
ActiveAdmin.register Deal do
# -- Form -----------------------------------------------------------
form do |f|
f.inputs "Brand (i.e. client)" do
f.input :brand_id, :label => "Select a brand:", :as => :select, :collection => Brand.all
end
it works great, and i can create Deals with a certain brand.
but I CAN'T manage to display the NAME of the Brand in my list of Deals:
ActiveAdmin.register Deal do
index do
selectable_column
# id_column
column :title
column :deal_amount
column :brand do |deal|
link_to deal.brand.name
end
...doesn't work.
How can I do that ?
I tried everything but i basically don't know how to fetch the name of a Brand given it matches the brand_id in the Deal's table.
Any help appreciated.
show do |f|
panel "Subject" do
attributes_table_for f, :name, :description, :is_visible
end
panel "Pages in List View" do
table_for(f.pages) do |page|
column :name
column :permalink
column :is_visible
end
end
panel "Pages in View " do
div_for(f.pages) do |page|
panel page.name do
attributes_table_for page, :name, :description, :is_visible
end
end
end
end
end
You can do nested relations in same style as parent model
A couple things seem missing:
class Deal < ActiveRecord::Base
belongs_to :brands, foreign_key: :brand_id, class_name: 'Brand'
end
This is assuming that you mean partner to be a Brand and your schema uses brand_id for that relationship.
In your form, you can simply use:
form do |f|
f.inputs "Brand (i.e. client)" do
f.input :partner, label: 'Select a brand:'
end
end
Your link_to call won't actually link to a url the way you have it.
column :brand do |deal|
link_to deal.partner.name, admin_brand_path(deal.partner)
# or simpler
auto_link deal.partner
end
I would highly recommend trying to be consistent in your naming, as it will make things a lot less confusing and will require less code to make things work. i.e.
class Deal < ActiveRecord::Base
belongs_to :brand
end
f.input :brand, label: 'Select a brand:'
auto_link deal.brand
And your DB column can still be named brand_id.

rails drop down menu association without db table ....

Respected ppl ...
i have these models :
class SanctionedPost < ActiveRecord::Base
attr_accessible :hospital_id, :sanctioned_posts, :designation_id
column :district_id
belongs_to:designation
belongs_to:hospital
belongs_to:district
belongs_to:division
end
class Hospital < ActiveRecord::Base
attr_accessible :beds, :fax_no, :hospital_name, :phone_no, :district_id, :institution_type_id, :location_id, :division_id, :block_id, :hospital_type_id, :IsAdministrativeLocation, :IsTribal, :latitude, :longitude
belongs_to:district
belongs_to:division
belongs_to:block
has_many:sanctioned_posts
end
class Division < ActiveRecord::Base
attr_accessible :division_name, :state_id
has_many:health_dept_locations
belongs_to:state
has_many:districts
has_many:hospitals
has_many:sanctioned_posts
validates_associated :districts
end
I want to be able to create dropdowns in my sanctioned_posts for such that divisions narrows down the districts which narrows down the blocks which narrows down to hospitals ...
(so that i dont have to select from a million hospitals ...) ...
I have tried everything from http://railscasts.com/episodes/88-dynamic-select-menus-revised and http://railscasts.com/episodes/193-tableless-model still to no avail ...
====================================
im using simple form ... and this allowed me to accomplish a similar task for the hospitals create form ...
<%= f.association :division,label_method: :division_name, value_method: :id, include_blank: false%>
<%= f.input :district_id do %>
<%= f.grouped_collection_select :district_id, Division.order(:division_name), :districts, :division_name, :id, :district_name, include_blank: true, label: 'District' %>
<% end %>
<%= f.input :block_id do %>
<%= f.grouped_collection_select :block_id, District.order(:district_name), :blocks, :district_name, :id, :block_name, include_blank: true, label: 'Block' %>
<% end %>
(+ the accompanying coffeescript... )
But in my current scenario im not able to do the same ...since im not storing division,district,block id in the sanctioned_posts model .... but i believe the hospital_id would be somewhat helpful in this context ....
Thnx very much in advance :) ...
Regards
Why not use CoffeeScript and JQuery to do REST requests on the index method and you can configure your routes accordingly?
Example: States have schools, schools have students
States have_many schools, schools have_many students
Select first state of Illinois. Illinois has ID of 11
get request to /states/11/schools.json
SchoolsController < ApplicationController
responds_to :json
def index
states = State.find(params[:id})
respond_with states.schools
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

ActiveAdmin forms (new/edit) belongs_to association?

I use Active Admin gem for Ruby on Rails.
I have modules Team and Coach, which have a has_many and belongs_to relationship.
class Team < ActiveRecord::Base
belongs_to :coach
end
class Coach < ActiveRecord::Base
has_many :teams
end
I figured out how to display first name and last name on index and show page (i did it like that:)
index do
column :name
column "Coach" do |team|
team.coach.firstname + " " + team.coach.lastname
end
default_actions
end
What i want is how to display first name and last name of coach in Team form (new and edit page) in dropdown menu?
Please help me with this.
Can you try this
f.input :coach_name, :as => :select, :collection => Coach.all.map {|u| [u.firstname, u.id]}, :include_blank => false
I had the same problem. The edit page shows object instances in the select menu such as,
#<Coach:0x00eff180c85c8>
To solve it and access each instance's fields use this,
form do |f|
f.inputs "Coaches" do
f.input :name
f.input :coach, member_label: Proc.new { |c| "#{c.firstname} #{c.lastname}"
end
f.actions
end
ActiveAdmin uses Formtastic and its documentation has more examples.
This stackoverflow answer helped me get this solution.
Try this:
f.input :coach_name, :as => :select, :collection => Coach.all.map {|u| [u.firstname.to_s, u.id]}

Resources