rails 5 way for having order and includes in has_many - ruby-on-rails-5

I have this line in rails 3:
has_many :balance_lines, :dependent => :destroy, :include => "budget_item", :order => "budget_items.position"
How do I convert it to rails 5?

This is the right way:
has_many :balance_lines, -> { order("budget_items.position").includes("budget_item") }, :dependent => :destroy

Related

polymorphic model but want multiple versions of it

I have a polymorphic asset model but would like two different versions of it for an asset class. Something like:
class Location < ActiveRecord::Base
has_many :assets, :as => :assetable, :order => 'position'
has_many :assets :known_as => :cover_images, :as => :assetable, :order => 'position'
I saw this question: Rails Polymorphic Association with multiple associations on the same model but when I implemented in Rails 3.1 with my models, it looked like:
has_many :assets, :as => :assetable, :order => 'position'
has_one :header_photo, :class_name => 'Asset', :as => 'assetable', :conditions => {:assetable_type => 'header_asset'}, :dependent => :destroy
Looking in console, I see:
SELECT `assets`.* FROM `assets` WHERE `assets`.`assetable_id` = 37 AND `assets`.`assetable_type` = 'Location' AND `assets`.`assetable_type` = 'header_asset' LIMIT 1
which is not what I want.
How would I do this? Is there syntax for handling this?
thx

Multiple has_many :through

In object model, I have
has_many :likes
has_many :hates
has_many :users, :through => :likes
has_many :users, :through => :hates
How do I get the list of users for likes? E.g. object.users <--- but how do I specify through likes or hates?
You need to give these two different associations different names. What about
has_many :likes
has_many :hates
has_many :likers, :through => :likes, :source => :user
has_many :haters, :through => :hates, :source => :user
It seems that I need to add source too. If not Rails will be looking for likers/liker in likes.
has_many :likes
has_many :hates
has_many :likers, :through => :likes, :class_name => 'User', :source => 'user'
has_many :haters, :through => :hates, :class_name => 'User', :source => 'user'
You can do it like :
has_many :user_likes, :through => :likes, :class_name => 'User'

RSpec testing non validating has_many through relationship

I have a many to many relationship between documents.
Say I have document1 and document2. I have a many to many table where there are parents and children.
document.rb
has_many :child_relationships, :class_name => "DocumentRelationship", :foreign_key => "child_id", :dependent => :destroy
has_many :parents, :through => :child_relationships, :source => :parent
has_many :parent_relationships, :class_name => "DocumentRelationship", :foreign_key => "parent_id", :dependent => :destroy
has_many :children, :through => :parent_relationships, :source => :child
document_relationship.rb
belongs_to :parent, :class_name => "Document", :foreign_key => "parent_id"
belongs_to :child, :class_name => "Document", :foreign_key => "child_id"
validates_uniqueness_of :child_id, :scope => [:parent_id]
validates_presence_of :parent_id
validates_presence_of :child_id
validate :obeys_chronology
def obeys_chronology
errors.add(:child_id, "must be created after its parent") if child_id.to_i < parent_id.to_i
errors.add(:child_id, "cannot be its own parent") if child_id.to_i == parent_id.to_i
end
If I say document2.children << document1 it appropriately fails validation, but I don't know how to write a test for this.
Is there a better way to do this?
Add it to the collection
document2.children << document1
document2.children.contain?(document1).should == false
Then make sure it's not in there.

Only one side of join table being saved?

In my app, User objects can follow each other, and be followed. The two relationships are distinct.
I'm seeing that when I set user_a.follows << user_b that user_b.followed_by.count still == 0. Why?
When I play in the console, I see:
$ jordan = User.new(:name=>"Jordan")
=> #<User id: nil, name: "Jordan">
$ matt = User.new(:name=>"Matt")
=> #<User id: nil, name: "Matt">
$ matt.followers << jordan
=> [#<User id: nil, name: "Jordan">]
$ matt.followers.first
=> #<User id: nil, name: "Jordan">
$ jordan.friends.first
=> nil
$ matt.save
SQL (14.1ms) INSERT INTO "users" ("name") VALUES (?) [["name", "Matt"]]
SQL (0.3ms) INSERT INTO "users" ("name") VALUES (?) [["name", "Jordan"]]
SQL (0.4ms) INSERT INTO "followings" ("followee_id", "follower_id") VALUES (?, ?) [["followee_id", nil], ["follower_id", 2]]
=> true
My objects are defined as:
class User < ActiveRecord::Base
has_many :follower_followee_rel,
:class_name => "Following",
:foreign_key => 'followee_id',
:dependent => :destroy
has_many :friends,
:through => :follower_followee_rel,
:source => :followee
has_many :followee_follower_rel,
:class_name => 'Following',
:foreign_key => 'follower_id',
:dependent => :destroy
has_many :followers,
:through => :followee_follower_rel,
:source => :follower
end
class Following < ActiveRecord::Base
belongs_to :followee,
:class_name => 'User'
belongs_to :follower,
:class_name => 'User'
end
Totally ignoring the second half of the relationship.
No errors are raised. What's going on?
Join relationships don't work unless the two models that are being joined have both already been saved. You can see on the 3rd line of the SQL that nil is being inserted for followee_id, as jordan doesn't yet have an id.
You would also need to save matt before you check jordan's friends, because doing matt.followers << jordan is treated as a modification of matt that doesn't effect anything else until matt is saved.
Implementing Michael Fairley's suggestion got ActiveRecord to build the relationship, but the relationship was still being defined wrong.
Final solution was to save the records in advance of joining them, and to fix the foreign keys, which were backwards.
Was:
has_many :follower_followee_rel,
:class_name => 'Following',
:foreign_key => 'followee_id',
:dependent => :destroy
has_many :friends,
:through => :follower_followee_rel,
:source => :followee
has_many :followee_follower_rel,
:class_name => 'Following',
:foreign_key => 'follower_id',
:dependent => :destroy
has_many :followers,
:through => :followee_follower_rel,
:source => :follower
Is now:
has_many :follower_followee_rel,
:class_name => 'Following',
:foreign_key => 'follower_id',
:dependent => :destroy
has_many :friends,
:through => :follower_followee_rel,
:source => :followee
has_many :followee_follower_rel,
:class_name => 'Following',
:foreign_key => 'followee_id',
:dependent => :destroy
has_many :followers,
:through => :followee_follower_rel,
:source => :follower
Change is found #
:follower_followee_rel, :foreign_key=>'followee_id'
and
:followee_follower_rel, :foreign_key=>'followee_id'

Rails 3 has_many through scope with joins returns unexpected results

I am trying to create scopes to find all Galleries by a specific category type, like "Style". Eventually, they will be chained to filter by multiple category types, but I can't get the first to work.
Here are the models:
Gallery:
has_many :gallery_categories, :class_name => "GalleryCategories", :dependent => :destroy
has_many :categories, :through => gallery_categories
has_many :colors, :through => gallery_categories, :source => :category, :conditions => {:type => "Color"}
has_many :styles, :through => gallery_categories, :source => :category, :conditions => {:type => "Style"}
...and many more types of categories...
Category:
:has_many :gallery_categories
:has_many :galleries, :through => :gallery_categories
GalleryCategories:
:belongs_to :gallery
:belongs_to :category
I am trying to do something like this in Gallery:
:scope :by_style, lambda {|style| joins(:styles).where(:category => {:name => style})}
Then, for example, I run
Gallery.by_style("Contemporary")
And I am returned 181 Galleries when there are only 40 Galleries, and in this example there should only be one returned with the style "Contemporary".
Here is the resulting SQL:
SELECT `galleries`.* FROM `galleries` INNER JOIN `gallery_categories` ON `galleries`.`id` = `gallery_categories`.`gallery_id` INNER JOIN `categories` ON `categories`.`type` = 'Style' WHERE `categories`.`name` = 'Contemporary'
Any ideas? Thanks in advance.