My models are below at present.
user.rb
class User < ActiveRecord::Base
has_many :authentications
end
authentication.rb
class Authentication < ActiveRecord::Base
belongs_to :user
belongs_to :social, polymorphic: true
end
facebook.rb
class Facebook < ActiveRecord::Base
has_one :authentication, as: :social
end
twitter.rb
class Twitter < ActiveRecord::Base
has_one :authentication, as: :social
end
Now thanks to polymorphic association, I can access either Twitter or Facebook objects from an Authentication object as follows:
authentication.social
Then I want to access the Twitter or Facebook object directly from a User object as well using the :through option to call single method like below:
user.socials
So I tried modifying the User model like the following two samples:
sample1
class User < ActiveRecord::Base
has_many :authentications
has_many :socials, through: :authentications, source: :social, source_type: "Twitter"
has_many :socials, through: :authentications, source: :social, source_type: "Facebook"
end
sample2
class User < ActiveRecord::Base
has_many :authentications
has_many :socials, through: :authentications, source: :social, source_type: ["Twitter", "Facebook"]
end
But neither approach worked.
How can I access those objects with a single method like user.socials?
I heard :source and :source_type are for using polymorphic association on :through.
If we have to use separate methods like user.twitters and user.facebooks instead of user.socials, I think those options are contradictory to their original concept.
Thanks in advance.
:edit
I'm using
ruby 2.1.2p95
Rails 4.2.0.beta2
This is a old question, but I believe it will help someone.
I didn't found a great solution, but I've reached a simple solution that may be a slow one.
You have to know all possibles entities associated to your (in your case) Authentication model. Then your User model should have a method named socials. You should have something like this:
class User < ActiveRecord::Base
has_many :authentications
has_many :twitters, through: :authentications, source: :social, source_type: "Twitter"
has_many :facebooks, through: :authentications, source: :social, source_type: "Facebook"
def socials
twitters + facebooks
end
end
Hope it helps someone! :D
Related
All of the references I've found either show me how to do it upon table creation, or are for a much earlier version of rails. Ideally, I'd like like the foreign_key to be named 'author_id' in the questions table to distinguish it from other users who may be leaving comments or answers later.
class Question < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :questions
end
You can create a new empty migration file in your terminal via rails generate migration RenameUserFkOnQuestion. Open it up and build your migration. This is a handy guide if you're not sure on the name of something.
def change
change_table :questions do |t|
t.rename :user_id, :author_id
end
end
Run the migration and head over to your models. You'll need to update your relationships like so:
class Question
belongs_to :author, class_name: 'User'
end
class User
has_many :questions, inverse_of: :author
end
Then you should be good to go.
I created a has_and_belongs_to_many association between users and projects so that a user would be able to join in on a project. The association table exists however, I am unsure how I would create the association.
View
Schema
I definitely must recommend you to not use has_and_belongs_to_many, because there is no way for you do to callbacks, validations and so on.
It is definitely nice to use a real join model and use has_many, through.
class User
has_many :project_users, dependent: :destroy
has_many :projects, through: :project_users
end
class Project
has_many :project_users, dependent: :destroy
has_many :users, through: :project_users
end
class ProjectUser
belongs_to :project, required: true
belongs_to :user, required: true
validates :project, uniqueness: { scope: :user }
end
This works very seamlessly, you can do:
User.update(project_ids: [1,5,6,7])
And it will join the user to these project unless any validations fail.
I started out a big project with these tables everywhere, after a few months we started running into duplication issues, bad state of records and it was a hot mess. Using a real join model is so worth it.
Since you have your project ID inside hidden you could just do this inside JOIN (post) action
def join
#project = Project.find(params[:project][:id])
current_user.projects << #project
end
so if you have instance of #project and instance of user - in my example it is current_user( for example if you use devise) then you would just assign them using operator <<
Here is the reference:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
Hope it helps
I am really confused about the difference between class_name and source options of has_many.
For class_name, it is said on the API doc that:
Specify the class name of the association. Use it only if that name can’t be inferred from the association name. So has_many :products will by default be linked to the Product class, but if the real class name is SpecialProduct, you’ll have to specify it with this option.
And for source:
Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, through: :subscriptions will look for either :subscribers or :subscriber on Subscription, unless a :source is given.
It seems that these two options have the same function, that is, to specify the class name of the association, except that source is only used for has_many :through, and class_name can be set in every has_many association.
If so, why it is necessary for has_many to have these two options with the very similar functions? Why just use class_name only to specify all the association name?
I searched in many places but could not find the answer. I also read Rails: difference between :source => ?? and :class_name => ?? in models ,but it still does not explain why it is necessary for the existences of both class_name and source.
Thanks in advance.
The key point is class_name specify the class name of the association where source specifies the source association name.
Example:
lass User < ActiveRecord::Base
has_many :listing_managers
has_many :managed_listings, through: :listing_managers, source: :listing
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers, source: :user
end
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :user
end
On the above code example user is class_name. When we are declaring has_many :managers, through: :listing_managers then rails is expecting there is either manager or managers association with in ListingManager . Since we want to use user association for creating managers we have to tell it to rails that make managers association using ListingManager's user association.
Here is another example that use class_name option
class User < ActiveRecord::Base
has_many :listing_managers
has_many :listings, through: :listing_managers
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers
end
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :manager, class_name:"User"
end
On the above code we are declaring belongs_to :manager association on ListingManager but there is no model named manager that's why we have to set class_name option. Now, since we have manager association on
ListingManager we don't need to set source option on Listing that we had to do on first example.
Hope above will help someone.
Actually I have two model
class Article < ActiveRecord::Base
has_many :experts
accepts_nested_attributes_for :experts
end
class Expert < ActiveRecord::Base
belongs_to :article
end
Now I want validates "Article should have atleast one Expert" while saving the record, how should i validate the associated model while saving the records?
I currently have application which allows users to upload an image.
Currently. each image belongs to a certain event, or in my case a certain week.
To reduce redundancy and server overload with the same image being uploaded multiple times, I would like to allow the user to upload (1) image and give them the option to assign it to multiple weeks that are load in the database.
Here is the setup now:
Creative Model
class Creative < ActiveRecord::Base
belongs_to :week
mount_uploader :image, CreativeUploader
end
Week Model
class Week < ActiveRecord::Base
has_many :creatives
end
The issue I am having is getting my application to pass multiple [week_id]'s to a single creative.
Should this be converted to a has_and_belongs_to_many relationship with a join table?
NestedForm
<%= creative_form.collection_select(:week_id, #campaign.weeks, :id, :start_at) %>
TIA
EDIT If it's a many-to-many relationship then your associations will look like this, and yes, you need a new join table.
Creative Model
class Creative < ActiveRecord::Base
has_and_belongs_to_many :week
mount_uploader :image, CreativeUploader
end
Week Model
class Week < ActiveRecord::Base
has_and_belongs_to_many :creatives
end