I have a simple many-to-many E-R described as below:
Model order.rb:
class Order < ActiveRecord::Base
has_many :cronologies
has_many :statuses, :through => :cronologies
end
Model cronology.rb:
class Cronology < ActiveRecord::Base
belongs_to :order
belongs_to :status
validates_uniqueness_of :order_id, :scope => :status_id
end
Model status.rb:
class Status < ActiveRecord::Base
has_many :cronologies
has_many :orders, :through => :cronologies
end
This code below lets me get all statuses assigned to an order.
#order.statuses
...but how to get statuses ordered by the "created_at" attribute of the cronology table?
#order.statuses.all(:order => "cronologies.created_at")
or put it into association if you always want it ordered this way.
class Order < ActiveRecord::Base
has_many :cronologies
has_many :statuses, :through => :cronologies, :order => "cronologies.created_at"
end
Related
My db schema:
tournaments(id, ...)
teams(tournament_id, id, ...)
matches(tournament_id, id, team_id_home, team_id_away, ...)
Models:
class Tournament < ActiveRecord::Base
has_many :teams, dependent: :destroy
has_many :matches, dependent: :destroy
...
end
class Team < ActiveRecord::Base
belongs_to :tournament
...
end
class Match < ActiveRecord::Base
belongs_to :tournament
has_many :teams
...
end
I would like to have the following data in my view:
match_id team_id_home team_id_away team_id_home_name team_id_away_name
So, I'm asking for help with the following query (I'm trying to get team's names, but having problem with joining):
#matches = #tournament.matches.where(:tournament => #tournament).joins(:teams).paginate(page: params[:page])
I'm fairly new to rails, but you should be able to setup your associations like this: (going from memory)
class Match < ActiveRecord::Base
belongs_to :tournament
has_one :home_team, :class_name => "Team", :foreign_key => "team_id_home"
has_one :away_team, :class_name => "Team", :foreign_key => "team_id_away"
end
#####
m = Match.first
m.away_team.team_name
m.home_tam.team_name
Or in your case:
#matches = #tournament.matches.paginate(page: params[:page])
I don't think you need the where function: the has_many association tells rails to only pull matching matches.
It is belongs_to, not has_one in Match model.
class Match < ActiveRecord::Base
belongs_to :tournament
belongs_to :home_team, :class_name => "Team", :foreign_key => "team_id_home"
belongs_to :away_team, :class_name => "Team", :foreign_key => "team_id_away"
end
class Team < ActiveRecord::Base
belongs_to :tournament
has_many :matches
end
Now I can use tournament.home_team.name in my view
Right now I have a rich many-to-many association with VideoVote as the independent record.
class VideoVote < ActiveRecord::Base
belongs_to :user
belongs_to :video
end
class User < ActiveRecord::Base
has_many :video_votes
has_many :voted_videos,
:through => :video_votes,
:source => :video
end
class Video < ActiveRecord::Base
has_many :video_votes
has_many :voted_users,
:through => :video_votes,
:source => :user
end
However, I want to trasform this into a polymorphic association where comments can also have many VideoVotes (I realize this is confusing, so I should probably change it to Votes). (also, a video will have many comments.) How should I do this?
You first want to add voteable_id:integer and voteable_type:string to your video_votes table.
Then your models will look like:
class VideoVote < ActiveRecord::Base
belongs_to :voteable, :polymorphic => true
end
class Comment < ActiveRecord::Base
has_many :video_votes, :as => :voteable
#code
end
class Video < ActiveRecord::Base
has_many :video_votes, :as => :voteable
#code
end
Then you can access them just like any other has_many:
#video.video_votes
#comment.video_votes
#etc.
I have a models User
class User < ActiveRecord::Base
has_many :ratings
has_many :rated_films, :through => :ratings, :source => :film
end
and Films
class Film < ActiveRecord::Base
has_many :users, :through => :ratings
end
I am looking to find all Films that have not been rated by the specified user, smth like
class Film < ActiveRecord::Base
has_many :users, :through => :ratings
named_scope :not_rated_by_user, lambda { |user|
{:joins => :users, :conditions => ['? NOT IN users', user]}
}
end
Film.not_rated_by_user(User.first)
I am not that familiar with SQL so am not quite sure if this could be achieved in a named scope.
Many thanks
Yuriy
I suppose you have a ratings table, which is your join table. Right? So you need something like:
class User < ActiveRecord::Base
has_many :ratings
has_many :rated_films, :through => :ratings, :source => :film
end
class Film < ActiveRecord::Base
has_many :ratings
has_many :users, :through => :ratings
named_scope :not_rated_by_user, lambda { |user_id| {
:include => :ratings,
:conditions => ['? NOT IN (ratings.user_id)', user_id]
}}
end
class Rating < ActiveRecord::Base
belongs_to :film
belongs_to :user
end
And you can use
Film.not_rated_by_user(User.first.id)
Please let me know if it helped. I haven't tested!
Consider the following models:
class Artist < ActiveRecord::Base
has_many :artist_events
has_many :events, :through => :artist_events
end
class Event < ActiveRecord::Base
has_many :artist_events
has_many :artists, :through => :artist_events, :order => 'artist_events.position'
end
class ArtistEvent < ActiveRecord::Base
default_scope :order => 'position'
belongs_to :artist
belongs_to :event
acts_as_list :scope => :artist
end
Is is possible to use ActiveScaffold to administer this type of relationship? The ArtistEvent model exists to define a hbtm relationship with additional attribute of position.
Thanks!
Jonathan
yes. after all, ArtistEvent is yet another model - and active scaffold can operate on it as long as you have routes and controllers on the join model.
I have a Service Types table containing id and name of a couple of dozen services.
I have a Projects table that has to have a list of Proposed Services, and a list of Accepted Services.
I know that I would use HABTM on both sides with a project_service_types table in between.
I can't quite figure out what to do when I have 2 different relationships between the same table. I suspect it uses the :join_table and :associated_forign_key, but I can't get it to work in my app.
thanks.
I solved it using HABTM...
class ServiceType < ActiveRecord::Base
has_and_belongs_to_many :accepted_projects, :class_name => "Project", :join_table => :projects_accepted_types
has_and_belongs_to_many :proposed_projects, :class_name => "Project", :join_table => :projects_proposed_types
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :accepted_types, :class_name => "ServiceType", :join_table => :projects_accepted_types
has_and_belongs_to_many :proposed_types, :class_name => "ServiceType", :join_table => :projects_proposed_types
end
While you can solve this with habtm, what you're talking about is the use-case for has_many :through. You want to attach a bit of information along with the relationship. To do this you create a join model that represents the relationship.
In the end this allows you to treat your service proposal as a first-class "thing" in your domain. When the service is accepted you can just change the status. This also saves a join.
Migration
create_table :project_services do |t|
t.references :project
t.references :service_type
t.string :status
end
Models
class ProjectService < ActiveRecord::Base
belongs_to :project
belongs_to :service
end
class Project < ActiveRecord::Base
has_many :project_services
has_many :accepted_services, :through => :project_services,
:conditions => { :status => 'accepted' }
has_many :proposed_services, :through => :proposed_services,
:conditions => { :status => 'proposed' }
end
class Service < ActiveRecord::Base
has_many :project_services
has_many :accepted_projects, :through => :project_services,
:conditions => { :status => 'accepted' }
has_many :proposed_projects, :through => :proposed_services,
:conditions => { :status => 'proposed' }
end
For that you'd probably want to use has_many :through as in:
class ProposedService < ActiveRecord::Base
belongs_to :project
belongs_to :service_type
class AcceptedService < ActiveRecord::Base
belongs_to :project
belongs_to :service_type
class Projects < ActiveRecord::Base
has_many :proposed_services
has_many :accepted_services
has_many :service_types, :through => :proposed_services
has_many :service_types, :through => :accepted_services
class ServiceTypes < ActiveRecord::Base
has_many :proposed_services
has_many :accepted_services
has_many :projects, :through => :proposed_services
has_many :projects, :through => :accepted_services
The many-to-many section here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
explains this in more detail. Hope this helps!