Rails has_many self referential - ruby-on-rails-3

I have an accounts model as follows (simplified):
class Account < ActiveRecord::Base
attr_accessible :account_number, :display_name, :master_account_id
has_many :child_accounts, :class_name => "Account", :foreign_key => "id"
belongs_to :master_account, :class_name => "Account", :foreign_key => "master_account_id"
end
#account.master_account is currently working correctly, but I also want to be able to access #account.child_accounts - what do I need to do in order to fix that?

I think it has to be the other way round:
class Account < ActiveRecord::Base
has_many :child_accounts, :class_name => "Account", :foreign_key => "master_account_id"
belongs_to :master_account, :class_name => "Account"
end

Related

Rails simplify a query to get user profile's first_name

I want to retrieve application.applicant.profile.first_name for the applicant and I'm not able to retrieve the profile attribute:first_name using applicant above.
Profile, application are connected by foreign key: user_id to user.Can someone suggest a way?
Here are my associations:
user.rb
class User < ApplicationRecord
has_many :applications
has_one :profile, -> { where role: 'user' }, dependent: :destroy
profile.rb
class Profile < ApplicationRecord
belongs_to :user, :class_name => 'User', :foreign_key => 'user_id'
job.rb
class Job < ApplicationRecord
has_many :applications, :dependent => :destroy
has_many :applicants, :through => :applications, :class_name => 'User'
application.rb
class Application < ApplicationRecord
belongs_to :job
belongs_to :applicant, :class_name => 'User', :foreign_key => 'user_id'
This line isn't correct...
has_one :profile, -> { where role: 'user' }, class_name: 'User', dependent: :destroy
It should be...
has_one :profile, -> { where role: 'user' }, dependent: :destroy
The class_name for :profile is Profile but you don't need to specify it as it can be derived from the symbol by rails.
After numerous permutations and combinations such as polymorphic, select & join statement or even by providing a SQL query, finally realised that it was as simple as a single statement as I knew the user_id of current user:
<% post.applications.each do |papplication| %>
<%= Profile.find_by_user_id(papplication.user_id).first_name %> <% end %>

has_many multiple foreign key search

User
#
Cars
belongs_to :father, :class_name => "User"
belongs_to :user
user = User.find(1)
Guys help I can get the user's cars by typing user.cars (searches cars using user_id) but how exactly can I get it to search using father_id?
Obviously I can do a Car.find_by_creator_id(...) but I wanted to know if there was a railish solution.
Thanks
You can set up the other side of the relations and specify :inverse_of for each in the User model. Something like
class User < ActiveRecord::Base
has_many :father_cars, :class_name => "Car", :inverse_of => :father
has_many :cars, :inverse_of => :user
# ...
end
Cars < ActiveRecord::Base
belongs_to :father, :class_name => "User", :inverse_of => :father_cars
belongs_to :user, :inverse_of => :cars
# ...
end
You can then access the :father relation with
u = User.find(1)
cars = user.father_cars

How do I setup a Rails association where one model belongs to two instances of another model?

I have two models ObjectA and ObjectB. ObjectB has two columns, a_1_id and a_2_id, which are both foreign keys to ObjectA. ObjectB belongs to each of these foreign ObjectA objects.
class ObjectA < ActiveRecord::Base
attr_accessible :player_1, :player_2, :subject, :turn
belongs_to :player_1, :class_name => "User"
belongs_to :player_2, :class_name => "User"
has_many :object_b, dependent: :destroy, :finder_sql => "SELECT * FROM object_bs where (a_1_id = #{id} or a_2_id = #{id})"
end
class ObjectB < ActiveRecord::Base
attr_accessible :a_1_id, :a_2_id
belongs_to :a_1_id, :class_name => "ObjectA"
belongs_to :a_2_id, :class_name => "ObjectA"
end
Is this the best way to setup the association?
Use the :foreign_key option:
belongs_to :player_1, :class_name => "User", :foreign_key => 'player1_id'
belongs_to :player_2, :class_name => "User", :foreign_key => 'player2_id'
#...
belongs_to :a_1_id, :class_name => "ObjectA", :foreign_key => 'a_1_id'
belongs_to :a_2_id, :class_name => "ObjectA", :foreign_key => 'a_2_id'

How do I delete a record from all tables it is referred to?

Good morning fellow Overflowers,
Small problem with model associations. I have these model associations:
class Categorization < ActiveRecord::Base
belongs_to :exhibit
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :categorizations
has_many :exhibits, :through => :categorizations
acts_as_indexed :fields => [:title]
validates :title, :presence => true, :uniqueness => true
end
class Exhibit < ActiveRecord::Base
has_many :categorizations
has_many :categories, :through => :categorizations, :source => :category
acts_as_indexed :fields => [:title, :bulb]
validates :title, :presence => true, :uniqueness => true
belongs_to :foto, :class_name => 'Image'
end
So, essentially Categorization ends up with these columns (date/time stamps omitted):
categorization_id, exhibit_id and category_id.
My problem is that when I delete an Exhibit, its reference on the Categorization table is not deleted thus getting a DB error on my view. I have to first unassign the Exhibit from any Category and then delete it safely. Or (given for example that the Exhibit I delete has :exhibit_id=>'1') when I give in the rails console: Categorization.find_by_exhibit_id(1).destroy
Thanks for any help!!
You can set the :dependent options on associations that you want Rails to follow when you delete their parents:
class Exhibit < ActiveRecord::Base
has_many :categorizations, :dependent => :destroy
...
end

Rails has_many find associated items

So, got 2 models:
class Match < ActiveRecord::Base
has_many :rounds
has_many :participations
has_many :players, :through => :participations
belongs_to :clan_1, :class_name => "Clan", :foreign_key => "clan_1_id"
belongs_to :clan_2, :class_name => "Clan", :foreign_key => "clan_2_id"
belongs_to :winner, :class_name => "Clan", :foreign_key => "winner_id"
belongs_to :league
belongs_to :tournament
validates :clan_1_id, :presence => true
validates :clan_2_id, :presence => true
scope :by_league, lambda { |league| where("league_id == ?",league.id) }
scope :by_tournament, lambda { |tournament| where("tournament_id == ?",tournament.id) }
scope :played, where("played is not NULL")
scope :not_played, where("played is NULL")
end
class Clan < ActiveRecord::Base
has_many :players
has_many :rounds_won, :class_name => "Round", :foreign_key => "winner_id"
has_many :rounds_blue, :class_name => "Round", :foreign_key => "clan_blue_id"
has_many :rounds_purple, :class_name => "Round", :foreign_key => "clan_purple_id"
has_many :matches_won, :class_name => "Match", :foreign_key => "winner_id"
has_and_belongs_to_many :leagues
has_and_belongs_to_many :tournaments
def matches
Match.where("clan_1_id = ? OR clan_2_id = ?",self.id, self.id)
end
def matches_lost
matches.where("winner_id != ?", self.id)
end
def matches_drawn
matches.played.where("winner_id is NULL")
end
end
and I want to fetch all clans, which taken part in match.
You're over thinking it. Rails makes it very easy for you to do this.
class Comment < ActiveRecord::Base
belongs_to :post
end
class Post < ActiveRecord::Base
has_many :comments
end
#post.comments
If you have a column in your comment table with "modelName"_id (eg post_id) rails with automatically hook up the foreign key.
All you have to do is call #model1.model2 assuming #model1 is an instance of the model1 object.
If you want to hook up the query yourself you could use the where() method.
#comments = Comment.where(:post_id => some_id)
If you alter your associations a little bit you can utilize includes() in scopes:
class Match < ActiveRecord::Base
belongs_to :clan_1, :class_name => "Clan"
belongs_to :clan_2, :class_name => "Clan"
end
class Clan < ActiveRecord::Base
has_many :one_matches, :class_name => 'Match', :foreign_key => :clan_1_id
has_many :two_matches, :class_name => 'Match', :foreign_key => :clan_2_id
end
Then you can add this scope:
class Clan < ActiveRecord::Base
scope :participated_in_match, includes(:one_matches, :two_matches).where("matches.id IS NOT NULL")
end
This isn't tested so please let me know if you get unexpected results.
Quite simply:
model_two_object = Model_2.first # For clarity only, change to suit your needs
model_two_object.models_1