merge ActiveRecord::Relation with ActiveRecord::Associations - activerecord

I have 2 models
class User < ActiveRecord::Base
has_many :games
def created_games
Game.where(created_by: self.id)
end
end
class Game < ActiveRecord::Base
belongs_to :user
end
u = User.take
joined_games = u.games
created_games = u.created_games
the variable joined_games is a instance of ActiveRecord::Associations, and created_games is an instance of ActiveRecord::Relation.
Is there any way I can join joined_games and created_games together?

Try adding a scope in User model
scope :joined_games, where(user_id: self.id, created_by: self.id)

Related

Rails polymorphic aliased associations

I would like to try set up this association:
# app/models/course.rb
class Course < ActiveRecord::Base
belongs_to :subjectable, polymorphic: true
end
# app/models/student.rb
class Student < ActiveRecord::Base
has_many :courses, as: :subjectable
end
# app/models/campus.rb
class Campus < ActiveRecord::Base
has_many :courses, as: :subjectable
end
But this did not read very well in the code.
#this seems fine
campus = Campus.last
campus.courses
#this dosent make much sense gramatically
student = Student.last
student.courses
Campuses offer Courses, but Students don't have courses they have subjects. Now they are the same thing under the covers they just don't read well.
How could I get it so that student.subejects would yield the same result as student.courses?
You can name the association as you want, you don't have to mach the associated class.
In this case, you have to tell ActiveRecord what the pointed class is :
# app/models/student.rb
class Student < ActiveRecord::Base
has_many :subjects, as: :subjectable, class_name: 'Course'
end

Versioning and polymorphic associations

I'm creating a second version of my app using using the following pattern:
class List < ActiveRecord::Base
has_many :listable_items
has_many :lists, through: :listable_items, source: :listable, source_type: 'List'
end
class ListableItem < ActiveRecord::Base
belongs_to :list
belongs_to :listable, polymorphic: true
end
module V2
class List < List
has_many :listable_items
has_many :lists, through: :listable_items, source: :listable, source_type: 'V2::List'
self.inheritance_column = :_non_existing_column
end
end
Module V2
class ListableItem < ListableItem
belongs_to :list, class_name: "V2::List"
belongs_to :listable, polymorphic: true
end
end
list = V2::List.find_by(slug: "people")
=> #<V2::List:0x007fd6e9007f18 id: 97, title: "People"....>
list.listable_items
=> [#<V2::ListableItem:0x007fd6e6497ec8 id: 2633, list_id: 97, listable_id: 100, listable_type: "List",....]
list.listable_items.first.listable
=> #<List:0x007fd6e4185868 id: 100,...>
I assume this is happening because of the class definition in the listable_type column of ListableItems. Is there a way to have it refer to the V2 version of the model instead of the one defined in the db column when I call the associated record?
adding
def listable_type
"V2::" + super
end
to the ListableItem class didn't change the class of the called listable.
The solution was to over-write the listable method, not the listable_type method. There may very well be a better way to do this, but this way worked for me.
Module V2
class ListableItem < ListableItem
belongs_to :list, class_name: "V2::List"
belongs_to :listable, polymorphic: true
def listable
("V2::" + listable_type).constantize.find(listable_id)
end
end
end

ActiveRecord - Finding all objects with shared attributes in a join model

I have three models
class Boat < ActiveRecord::Base
belongs_to :captain
has_many :boat_classifications
has_many :classifications, through: :boat_classifications
end
class Classification < ActiveRecord::Base
has_many :boat_classifications
has_many :boats, through: :boat_classifications
end
class BoatClassification < ActiveRecord::Base
belongs_to :boat
belongs_to :classification
end
I'm trying to write a simple ActiveRecord query to find all the boats of type sailboat. Something like Boat.where(classifications: "Sailboat")
I think this could work:
Boat.joins(:classifications).where(classifications: { name: 'Sailboat' }) # name or whatever field contains Sailboat
Generates this query:
SELECT `boats`.* FROM `boats` INNER JOIN `boat_classifications` ON `boat_classifications`.`boat_id` = `boats`.`id` INNER JOIN `classifications` ON `classifications`.`id` = `boat_classifications`.`classification_id` WHERE `classification`.`name` = 'Sailboat'
I think you want something like this:
Boat.includes(:classifications).where(classifications: {id: Classification.sailboats})
For this to work, you also need a scope on Classification like this:
def self.sailboats
where(name: "Sailboat")
end

rails belongs_to through via association

I'm on rails 3.0 and trying to figure out what would be the proper way to setup a belong_to :through relationship (which) I know is not possible. Here's an example:
class ParentCompany < ActiveRecord::Base
has_many :subsidiaries
has_many :employees, :through => :subsidiaries
end
class Subsidiary < ActiveRecord::Base
belongs_to :parent_company
has_many :employees
end
class Employee < ActiveRecord::Base
belongs_to :subsidiary
belongs_to :parent_company, :through :subsidiary # <-- I know this is invalid
end
I know I can solve it by doing:
class Employee < ActiveRecord::Base
def parent_company
subsidiary.parent_company
end
end
However, I'd like to know if I can do the above via associations.
You can use delegate to accomplish this without using an association
class Employee < ActiveRecord::Base
belongs_to :subsidiary
delegate :parent_company, to: :subsidiary
end

ActiveRecord :through to set default values on through table

I would like to set a default value in a has_many through association.
Lets say I have three models:
People
Friends
Dogs
A person can request that a dog becomes their friend.
So a person would create an association where friends has an active column = false.
User
has_many :friends
has_many :dogs, :through => :friends
Now when I assign a dog to a user
User.find(1).dogs << dog
The friends table has null in the active column.
My friends model is defined as
Friend
def initialize(args = {})
super(args)
active = false
end
yet this does not work because the friend object is never created. Do I have to manually create one?
To set default values of a model; In the model I do this
before_save :default_values
private
def default_values
self.status = :active unless self.status
end
Not sure if this is the correct approach though.
With the following code you'll create a new friend with active = false
class User < ActiveRecord::Base
has_many :friends, :conditions => "active = false"
has_many :dogs, :through => :friends
end
#user = User.new
#user.friends.create #or #user.friends.build

Resources