How can I reference the same model twice and create the association in a multiple select form? - ruby-on-rails-3

I have two classes (Game and Report) and want to link them with an additional attribute (default = yes or no).
The game should then have default_reports and optional_reports.
The association is then updated by selecting the default and optional reports in a select (multiple) in the games create/edit form.
I have tried using has_many and through as well as polymorphic associations, but nothing seems to fit the use case, where the associated objects are fixed and you only want to manage associations.
class Game < ActiveRecord::Base
has_many :game_reports
has_many :reports, :through => :game_reports
end
class Report < ActiveRecord::Base
has_many :game_reports
has_many :games, :through => :game_reports
end
class GameReport < ActiveRecord::Base
belongs_to :game
belongs_to :report
end
Any help is appreciated!
Thanks

this is just the model. the view and form to create the records is an entirely different matter.
you can always add a conditions option to has_many. I'm assuming you're going to add default to game_reports so change your class to something like.
class Game < ActiveRecord::Base
has_many :game_reports
has_many :reports, :through => :game_reports
has_many :default_reports, through: :game_reports, source: :report, conditions: { game_reports: { default: true } }
end

Rails 4.2+, use a Polymorphic association with scope and specify the foreign_key and foreign_type options.
class GameReport
belongs_to :report, :polymorphic => true
end
class Game
has_many :game_reports, :as => :report, :dependent => :destroy
has_many :reports, -> { where attachable_type: "GameReport"},
class_name: GameReport, foreign_key: :game_report_id,
foreign_type: :game_report_type, dependent: :destroy
end
Other approachs:
Rails Polymorphic Association with multiple associations on the same model

Related

Class with nested association to itself

I have a class with a nested association to itself:
class Location < ActiveRecord::Base
has_many :location_gateways
has_many :gateways, through: :location_gateways, class_name: "Location", :dependent => :destroy
accepts_nested_attributes_for :gateways, reject_if: :all_blank, allow_destroy: true
belongs_to :location, optional: true
end
The connecting model:
class LocationGateway < ActiveRecord::Base
belongs_to :location, :class_name => "Location"
belongs_to :gateway, :class_name => "Location"
end
Now I would like to make a form that can create a Location and some gateways but I get an Gateway must exist error when I submit it (the call to Location.new)
I'm assuming this is because the model Gateway doesn't exist. How can I make rails understand that it should create another Locationand not a Gateway?
Found no way around this error. I had to make a new class Gateway that inherits from Location and add a type to Locations (STI).

N + 1 Queries even with Eager loading in Rails 3.2

I have a has_many through, through relationship that needs to be eagerly loaded. Is this possible in Rails 3.2? I've tried several ways to include the association yet calling categories on the facebook_user object always makes another query to Category. Here's a simplified version of my activerecord associations.
class FacebookUser < ActiveRecord::Base
belongs_to :user, touch: true
has_many :user_categories, through: :user
has_many :categories, through: :user_categories
end
class User < ActiveRecord::Base
has_many :user_categories
has_many :categories, through: :user_categories
has_one :facebook_user
end
class UserCategory < ActiveRecord::Base
belongs_to :user
belongs_to :category
end
#single query
FacebookUser.includes( user: :categories).joins(user: :categories).each do |f|
## N+1 query on f.categories
f.categories.first
end
#multi-part query
facebook_user_ids = FacebookUser.where(user_id: [1,2,3]).joins(user: :categories).pluck('facebook_users.id')
FacebookUser.where( id: facebook_user_ids ).includes( user: :categories)
With
FacebookUser.includes( user: :categories)
you have eager loaded the user and his categories instead of the categories on facebook_user. So in order to avoid n+1 query you call then
f.user.categories
So why u just don't eager facebook_user's categories?
FacebookUser.includes(:categories)

What's the rails way to include a field in a join model when listing an association?

So if I have the following relationship
class Item < ActiveRecord::Base
has_many :item_user_relationships
has_many :users, :through => :item_user_relationships
end
class User < ActiveRecord::Base
has_many :item_user_relationships
has_many :items, :through => :item_user_relationships
end
class ItemUserRelationship < ActiveRecord::Base
belongs_to :item
belongs_to :user
attr_accessible :role
end
What's the rails way to include the role attribute when listing all the Users of an Item?
#users = #item.users # I want to include the role as part of a user
Thanks!
UPDATE: I'm still having trouble with this. My goal is to get an array of User models that have their role included in the attributes.
I'm note sure if I understand you correctly, but maybe this is what you want?
#users = #item.users
#users.each do |user|
puts user.item_user_relationships.first.role
end

ActiveRecord Find with condition based on associated record having a value in a list

With the following Rails models:
class Group < ActiveRecord::Base
has_many :group_locations, :dependent => :restrict
has_many :locations, :through => :group_locations, :dependent => :restrict
end
class Location < ActiveRecord::Base
has_many :group_locations, :dependent => :destroy
has_many :groups, :through => :group_locations
end
class GroupLocation < ActiveRecord::Base
belongs_to :group
belongs_to :location
end
I am trying to Find all of the locations that are associated with at least one of several groups contained in the string "group_list" (e.g. "1,2,3,4,5"). If it was a field from the Location record, I would specify a condition of "*field in (#{group_list})*". But how do I accomplish my goal when I want to have at least one of the location's "group_location" whose "group_id" is in the list (or, alternatively, one "group" whose group_id is in the list).
I know how to do it with pure SQL, but how do you do it with Rails?
#taro You are right. Started by adding the code
joins(:group_locations).where("group_id in (?)", group_id_array)
Then I proceeded to define a scope just to make it a nice package:
scope :locations_in_groups, lambda { |grparray| joins(:group_locations).where("group_id in (?)", grparray) }
Thanks for your help.

Has_many, through association

Warning:Total Rails Newb (TRN). This should be a pretty basic question so I'm hoping someone can spare a couple mins to help shed some light.
Let's say I have the following models: User, Group, and Member
A user can have many groups (let's say friends, family, etc)
A group can have many members, namely other users.
How would I structure this?
Initially I tried this:
class User < ActiveRecord::Base
has_many :groups
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :users, :through => :members
belongs_to :user
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
However this gave me an error in User so I changed
has_many :groups, :through => :members
to
has_many :memberships, :through => :members, :source => :groups
Still getting an error about missing association when I try to do
group = Group.new
group.user.new
It will be useful: http://railscasts.com/episodes/47-two-many-to-many
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
has_many :groups_as_owner, :class_name => "Group"
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
belongs_to :owner, :class_name => "User", :foreign_key => :user_id
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
basically has_many-through associations are n:m associations (join-tables) that (shall) have more attributes than just the id's of the joined record ids...
so you have a table Groups (with an id), a table Users (with an id) and a table Members (no id, but user_id and group_id)
basically, what you did is nearly correct, just think about how you access a group from a user or vice versa....
a user would first look up its member information and through that member information get access to the group information ... and vice versa for a group
so you first set up
has_many :members
and then call
has_many :groups, :through => :members
all you need is
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
and you have another bug in your code above
you might want to use
user = group.users.new
instead of
user = group.user.new
Try this structure:
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
Also take a look at has_and_belongs_to_many, if you don't need to do with class Member then you should use has_and_belongs_to_many. In this case don't forget to create joining table in the database