Rails: Polymorphic Associations: How to list associations - ruby-on-rails

I have a polymorphic assocation:
class User < ActiveRecord::Base
belongs_to :companiable, :polymorphic => true
end
class Agency < ActiveRecord::Base
has_many :users, :as => :companiable
end
class Publisher < ActiveRecord::Base
has_many :users, :as => :companiable
end
and now I want to list all users and show the company they belong to. Is there a more elegant solution than this (strongly hope there is)?
def index
#publishers = Publisher.all
#agencies = Agency.all
#users = User.all
end
...
<td><% unless user.companiable_id.nil? %>
<% if user.companiable_type == "Agency" %>
<%= #agencies[user.companiable_id].name %>
<% elsif user.companiable_type == "Publisher"%>
<%= #publishers[user.companiable_id].name %>
<% end %>
<% end %>
</td>

You can acces the company from user, since the belongs_to adds a method so that you can access the other object directly by doing user.companiable
def index
#users = User.all
end
and in your view
<td><% unless user.companiable.nil? %>
<%= user.companiable.name %>
<% end %></td>

Related

I want to get the data from many to many table

I want to get the data from many to many relationship table (Tag-Service-Category) like this below in tag/show.html.erb.
class Tag < ActiveRecord::Base
has_many :service_tags
has_many :services, through: :service_tags
end
class ServiceTag < ActiveRecord::Base
belongs_to :service
belongs_to :tag
end
class Service < ActiveRecord::Base
has_many :service_tags
has_many :tags, through: :service_tags
has_many :service_categories
has_many :categories, through: :service_categories
end
class ServiceCategory < ActiveRecord::Base
belongs_to :service
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :service_categories
has_many :services, through: :service_categories
end
I wrote the code like this, but it`s not working.
#tag = Tag.find(params[:id])
<% #tag.services.each do |service| %>
<% service.categories.each do |category| %>
<span class="category" class="<%= category.id %>"><%= category.name %></span>
<% end %>
<% end %>
controllers/tags_controller.rb
class TagsController < ApplicationController
def show
#tag = Tag.find(params[:id])
#tags = Tag.all
end
end
Although you have the db relationships correct, you'll still need to call out the connecting model. Because you're doing a double many to many relationship you'll need to create an in-between array. Try adding this to your view:
<% services_array = [] %>
<% #tag.service_tags each do |service_tag| %>
<% services_array << service_tag.service %>
<% end %>
<% services_array.each do |service| %>
<span class="category">
<%= service.service_category.category.id %>
<%= service.service_category.category.name %>
</span>
<% end %>

Eager-loading with many-to-many relationship

I have 3 models:
class Thing < ActiveRecord::Base
has_many :products
has_many :shops, through: :products
end
class Product < ActiveRecord::Base
belongs_to :thing
belongs_to :shop
end
class Shop < ActiveRecord::Base
has_many :products
has_many :things, through: :products
end
Shop sales many things. Every shop has its own page with the list of its things. Products table has shop_id, thing_id, things quantity and thing price.
Here is controller:
def show
#shop = Shop.find(params[:id])
end
And view:
<% #shop.things.each do |thing| %>
<%= link_to thing.name, shop_thing_path(id: thing.id, shop_id: #shop.id) %><br>
<%= thing.products.find_by(shop_id: #shop.id).price %><br>
<%= thing.products.find_by(shop_id: #shop.id).quantity %>
<% end %>
I can't understand how to eager load this right. Now i get N * 2 queries (N = things count):
SELECT "products".* FROM "products" WHERE "products"."thing_id" = ? AND "products"."shop_id" = 1 LIMIT 1
def show
#shop = Shop.includes(:things).find(params[:id])
end
Here is the documentation related to eager loading.
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
I tried to go from another point and use #products instead of #shop.things:
Controller:
def show
#shop = Shop.find(params[:id])
#products = #shop.products.includes(:thing).joins(:thing)
end
View
<% #products.each do |product| %>
<tr>
<td><%= link_to product.thing.name, shop_thing_path(id: product.thing_id, shop_id: product.shop_id) %></td>
<td><%= product.price %></td>
<td><%= product.quantity %></td>
</tr>
<% end %>
Now that works. But i still can't understand why
def show
#shop = Shop.includes(:things).find(params[:id])
end
doesn't work.

Accepts nested attributes for multiple records

I have two resources: Recommendations and Ratings.
Recommendations Model:
class Recommendation < ActiveRecord::Base
has_many :ratings
accepts_nested_attributes_for :ratings
end
Ratings Model:
class Rating < ActiveRecord::Base
belongs_to :recommendation
end
Recommendations Controller:
class RecommendationsController < ApplicationController
def index
#product = Product.find(params["product_id"])
#recommendations = Recommendation.find(:all, :joins => :products, :conditions => ["product_id = ?", (params["product_id"])])
#recommendation = Recommendation.new
#rating = Rating.new
end
def create
#need to find_or_create new rating based on recommendation_id
end
end
Recommendations Index:
<div id ="prods_container">
<%= form_for #recommendation do |f| %>
<%= f.fields_for #rating do |r| %>
<% #recommendations.each do |rec| %>
<%= rec.title %>
<div id="rec_note_text"><%= r.text_field :notes %></div>
<% end %>
<%= f.submit %>
<% end %>
<% end %>
</div>
I am trying to add a notes field for each of the "recommendation" objects which I need to update the ratings table in my create action/recommendations controller. How do I pass the correct ID's to my controller to achieve this?

Rails: Create form for #score while in different model no direct associations

I want to create a multiple form for editing scores from a different model.
The main model is a Formrule model that consists of a habtm association with a Scoretype model
and has a habtm association with a Room model.
Both models are used to query a Scores model resulting in a #scores instance. It is for this instance I want to create a form, but the problem is that no field_for are being created. I know that the #scores is populated correctly, but the form does not show up.
This is the form as I have it now
<%= form_tag '/scores/update_scores' do %>
<table>
<tr>...</tr>
<% for score in #scores %>
<% fields_for :scores, score do |score| %>
<tr>
<td>
<%= score.hidden_field(:form_id) %>
<%= score.hidden_field(:team_id) %>
<%= score.hidden_field(:scoretype_id) %>
</td>
<td>
<%= score.number_field :scorevalue %>
</td>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag 'Update' %>
<% end %>
And these are the Models:
Formrule
class Formrule < ActiveRecord::Base
belongs_to :form
has_and_belongs_to_many :scoretypes
has_and_belongs_to_many :rooms
has_many :teams, :through => :rooms
end
Scoretype
class Scoretype < ActiveRecord::Base
has_many :scores
has_and_belongs_to_many :formrules
end
Room
class Room < ActiveRecord::Base
has_many :teams
has_and_belongs_to_many :formrules
end
Team
class Team < ActiveRecord::Base
has_many :scores
belongs_to :room
belongs_to :group
end
Score
class Score < ActiveRecord::Base
belongs_to :form
belongs_to :team
belongs_to :scoretype
validates_uniqueness_of :id, :scope => [:team, :scoretype]
end
And finally, the used controller (Formrule)
def show
#formrule = Formrule.find(params[:id])
#scoretypes = #formrule.scoretypes.all.collect
#rooms = #formrule.rooms.all.collect
#teams = Team.find(:all, :conditions => {:room_id => #rooms})
#scores = Score.order("team_id").all(:conditions => {:scoretype_id => #scoretypes, :team_id => #teams})
...
end
Why is the form not showing up? any suggestions?
Thank you all in advance!
Try using <%= fields_for ... %> instead of <% fields_for ...%>.

form_for for relation table with type of many to many relation

My goal is to display select box for each relation for users and specific project.
All users need to be listed but only project users have some type of relation. Other users have none selected in theirs select box.
I have this model:
class Project < ActiveRecord::Base
belongs_to :company
has_many :tasks, :order => 'state_type_id ASC'
has_many :project_user_relations
has_many :users, :through => :project_user_relations
def t_name
name.camelcase
end
end
class User < ActiveRecord::Base
belongs_to :company
has_many :tasks , :foreign_key => :assigned_user_id
has_many :project_user_relations
has_many :projects, :through => :project_user_relations
def full_name
firstname + ' ' + lastname
end
def relation_to(project)
relation=ProjectUserRelation.find_by_project_id_and_user_id(project.id, id)
relation ||= relation=ProjectUserRelation.new
end
end
class ProjectUserRelation < ActiveRecord::Base
belongs_to :project
belongs_to :user
has_one :project_user_relation_type
end
class ProjectUserRelationType < ActiveRecord::Base
def t_name
I18n.t("app.projects.users.relation.type."+code)
end
end
I want make a form to display all users, with collection_select.
I used code:
def edit_all
#project = Project.find(params[:project_id])
#users = User.all
....
in my controler
routes works ok.
in my view:
<% #users.each do |user| %>
<%= f.fields_for :users, user do |user_fields| %>
<tr class="reference" rel="<%= parent_user_path(user) %>" >
<td class="name"><%= link_to user.full_name, parent_user_path(user) %></td>
<td class="email"><%= mail_to user.email %></td>
<td class="type">
<%= user_fields.fields_for user.relation_to #project do |relation_fields| %>
<%= relation_fields.collection_select :project_user_relation_type, ProjectUserRelationType.all, :id, :t_name, {:include_blank => false, :prompt => t("helpers.select.prompt") } %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
or for test:
<%= f.fields_for :users, #users do |xuser_fields| %>
<% logger.debug "#{self.to_s} xuser_fields = #{xuser_fields.object.inspect} ;" %>
<tr>
<td><%= xuser_fields.text_field :firstname %></td>
<td></td>
<td></td>
<td></td>
</tr>
<% end %>
but notnihng woks right
first one generates wrong name in html:
select id="project_users_project_user_relation_project_user_relation_type" name="project[users][project_user_relation][project_user_relation_type]"
second one generates error:
undefined method `firstname' for # Array:0x4d03658
Can you help me to solve this situation.
PS:sorry for long code :(
SOLUTION (probably - solved by reading RoR sources)
I found sollution i thing.
A method
def name_attributes=(attributes)
# Process the attributes hash
end
in Project model was missing.
It is unbelievable sollution :].
There is also exact syntax after fields_for: :name, #some_collection, where name must be exactly same name as in the beginign of mentioned def in Model.

Resources