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.
Related
I have a User model, a Listing model and an Order model. A user can either place an order or publish a listing which others can place an order for. Thus, a User can be customer as well as supplier.
My Order model has listing_id, from_id and to_id.
My question is, how can I set up associations between these models ? I read the rails guide on associations but the example there were dealing with separate customer and supplier models.
class User < ActiveRecord::Base
has_many :listings, :foreign_key => :supplier_id, :inverse_of => :supplier
has_many :orders, :foreign_key => :customer_id, :inverse_of => :customer
end
class Listing < ActiveRecord::Base
belongs_to :supplier, :class_name => 'User'
belongs_to :order
end
class Order < ActiveRecord::Base
belongs_to :customer, :class_name => 'User'
has_many :listings
end
I've got a Person who can be linked to many Structures (structure is polymorphic)
I've got a Venue, who can have many People, as a structure.
I've got a Journal, who can have many People, as a structure.
Here is my modelization :
class Venue < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Journal < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Person < ActiveRecord::Base
has_many :structure_people
has_many :structures, :through => :structure_people
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :person
end
My problem :
when i try to get people on a Venue or on a Journal, it works. Cool :)
BUT
when i try to get structures on a person, i've got an error :
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'Person#structures' on the polymorphic object 'Structure#structure'.
Anyone could help me to solve this ?
Thanks a lot.
Christophe
I think it's a restriction of Rails, because has_many association will guess a class_name automatically. But polymorphic association may returns multiple class_name. Do you mind use this:
class Person < ActiveRecord::Base
has_many :structure_people
has_many :venues, :through => :structure_people
#Journal is the same.
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :venue, :foreign_key => 'structure_id', :conditions => {:structure_type => 'Venue'}
belongs_to :person
end
Although it is an ugly solution...
I think you can choose an alternative way.
class Person < ActiveRecord::Base
has_many :structure_people
def structures
structure_people.map(&:structure)
end
end
You can't get chaining function of has_many, but you can get polymorphic structures :)
I have 3 models: User, Object, Likes
Currently, I have the model: a user has many Objects. How do I go about modeling:
1) A user can like many objects
2) an Object can have many likes (from different users)
So I want to be able to do something like this:
User.likes = list of objects liked by a user
Objects.liked_by = list of Users liked by object
The model below is definitely wrong...
class User < ActiveRecord::Base
has_many :objects
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
belongs_to :users
has_many :users, :through => :likes
end
To elaborate further on my comment to Brandon Tilley's answer, I would suggest the following:
class User < ActiveRecord::Base
# your original association
has_many :things
# the like associations
has_many :likes
has_many :liked_things, :through => :likes, :source => :thing
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :thing
end
class Thing < ActiveRecord::Base
# your original association
belongs_to :user
# the like associations
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
end
You are close; to use a :through, relation, you first must set up the relationship you're going through:
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
has_many :likes
has_many :users, :through => :likes
end
Note that Objects should has_many :likes, so that the foreign key is in the right place. (Also, you should probably use the singular form Like and Object for your models.)
Here is a simple method to achieve this. Basically, you can create as many relationships as needed as long as you specify the proper class name using the :class_name option. However, it is not always a good idea, so make sure only one is used during any given request, to avoid additional queries.
class User < ActiveRecord::Base
has_many :likes, :include => :obj
has_many :objs
has_many :liked, :through => :likes, :class_name => 'Obj'
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :obj
end
class Obj < ActiveRecord::Base
belongs_to :user
has_many :likes, :include => :user
has_many :users, :through => :likes
# having both belongs to and has many for users may be confusing
# so it's better to use a different name
has_many :liked_by, :through => :likes, :class_name => 'User'
end
u = User.find(1)
u.objs # all objects created by u
u.liked # all objects liked by u
u.likes # all likes
u.likes.collect(&:obj) # all objects liked by u
o = Obj.find(1)
o.user # creator
o.users # users who liked o
o.liked_by # users who liked o. same as o.users
o.likes # all likes for o
o.likes.collect(&:user)
Models & associations as per naming conventions of rails modeling
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Object < ActiveRecord::Base
belongs_to :user
has_many :likes
has_many :users, :through => :likes
end
Also, you can use of already built-in gems like acts-as-taggable-on to have same functionality without code :)
I have item, region and category table they are join through item_region ans item_category table their relationship is as follow
class Item < ActiveRecord::Base
has_many :item_region
has_many :region, :through => :item_region
has_many :item_category
has_many :category, :through => :item_category
class Region < ActiveRecord::Base
has_many :category
has_many :item, ::through => :item_category
class ItemRegion < ActiveRecord::Base
belongs_to :item
belongs_to :region
end
class Category < ActiveRecord::Base
has_many :item, :through => :item_category
has_many :item_category
class ItemCategory < ActiveRecord::Base
belongs_to :item
belongs_to :category
end
I want to find all fields of item and category_name and region_name from region_id,category_id and item_id using join table.
Thanks.
I hope I got this one correct. What about obtaining the required item, then the desired region and category from it.
item = Item.find(item_id)
region = item.regions.where(:id => region_id)
category = item.categories.where(:id => category_id)
Another suggestion, you are better off providing plural form for your associations. Its intuitive to do object.collections for a has_many association. Note that Rails will still function with above code but that doesn't follow CoC(convention over configuration) principle of Rails. If you follow the convention, you wouldn't have to do a lot of configurations.
Check the examples here http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
Personally, I'd prefer to have my associations in Item model as :
class Item < ActiveRecord::Base
has_many :item_regions
has_many :regions, :through => :item_regions
has_many :item_categories
has_many :categories, :through => :item_categories
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.