I have a strange requirement in my project. Actually, I have two tables (users,galleries). I would like to access galleries table with has_one as well as has_many associations. The main purpose is to get the profile snap of the user by using has_one relation and to get the personally uploaded pictures by using has_many relation.
Initially I go with polymorphic association to resolve this (FYI, please find the below code snippet) .But I think it is not the right approach for this problem.
Would anybody explain how to handle this case in an efficient way.
class User < ActiveRecord::Base
attr_accessible :name
has_many :galaries, as: :imageable
has_one :galary, as: :imageable
end
class Galary < ActiveRecord::Base
attr_accessible :name
belongs_to :imageable, polymorphic: true
end
You need to add a column user_id in galaries table in order to link the the user to the galary (profile snap).
rails generate migration add_user_id_to_galaries user_id:string
This will generate the migration:
class AddUserIdToGalaries < ActiveRecord::Migration
def change
add_column :galaries, :user_id, :integer
end
end
Then run rake db:migrate
Moving to our Models now:
class User < ActiveRecord::Base
attr_accessible :name
has_many :galaries, as: :imageable
has_one :galary #profile snap
end
class Galary < ActiveRecord::Base
attr_accessible :name
belongs_to :imageable, polymorphic: true
belongs_to :user #profile snap user
end
Can be done with scoped has_one association. Although not necessary, you can define which gallery is selected in the has_one using a scope. If no scope is given, the has_one would return the first match.
class User < ActiveRecord::Base
attr_accessible :name
has_many :gallaries
has_one :gallery, -> { where primary: true }
end
class Gallery < ActiveRecord::Base
#user_id, primary (boolean variable to select the gallery in has one association)
attr_accessible :name
belongs_to :user
end
Related
What is the preferred way of selecting a specific record out of a has_many relation for a specific model in Rails? (I'm using Rails 5.)
I have a model User and a model Picture which are related via the following code:
class User < ApplicationRecord
has_many :pictures, as: :imageable
# ...
end
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
# ...
end
What I want to do is to allow a User to set a profile picture from the images associated with it, so I can call #user.profile_picture on a User object and retrieve the profile picture.
You can add an additional one-to-one relationship.
# create by running:
# rails g migration AddPrimaryPictureToUser
class AddPrimaryPictureToUser < ActiveRecord::Migration[5.0]
def change
add_column :users, :primary_picture_id, :integer
add_index :users, :primary_picture_id
add_foreign_key :users, :pictures, column: :primary_picture_id
end
end
class User < ApplicationRecord
has_many :pictures, as: :imageable
# This should be belongs_to and not has_one as the foreign key column is
# on the users table
belongs_to :primary_picture,
class_name: 'Picture',
optional: true
end
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_one :primary_user,
foreign_key: 'primary_picture_id',
class_name: 'User'
# ...
end
The main reason to do it this way vs for example a boolean flag on the pictures table is that having a separate relationship makes it easy to join which is important for avoiding N+1 queries which is an issue if you are listing a bunch of users together with their primary image.
#users = User.includes(:primary_picture).all
I have three models : User, Agency and Client.
Currently,
class User < ActiveRecord::Base
has_one :agency
has_one :client
end
class Client < ActiveRecord::Base
belongs_to :users
end
class Agency < ActiveRecord::Base
belongs_to :users
end
I want to change associations and create a polymorphic association such as this:
User belongs_to :role , :polymorphic => true
and
Client has_one :user, as: :role
Agency has_one :user, as: :role
I am a novice rails developer. How can I achieve this? HOw to write a migration?
You need to add two fields, role_id and role_type in user model. You can create new migration as follows
rails g migration addNewFieldsToUsers role_id:integer role_type:string
After running rake db:migrate you need to modify the associations as follows
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true
end
class Client < ActiveRecord::Base
has_one :user, as: :role, class_name: 'User'
end
class Agency < ActiveRecord::Base
has_one :user, as: :role, class_name: 'User'
end
Now restart the rails server.
A migration is not needed. There are no associations between models in the database (which is what a migration would change).
What you need to do is change the models app/models/user.rb and app/models/location.rb. simply remove the belongs_to: from user and add it in loction: belongs_to: user.
I have a parent model called Quote. which has an attribute called final_quote and has a child model called QuoteBoms, which has attributes called quote_final_quote and quantity and total_quote (=quote_final_quote * quantity)
class Quote < ActiveRecord::Base
has_many :quote_boms, dependent: :destroy
accepts_nested_attributes_for :quote_boms, :reject_if => :all_blank, :allow_destroy => true
class QuoteBom < ActiveRecord::Base
belongs_to :quote
has_many :quotes
end
Now in the nested model, I am selecting the quote with the association "belongs_to :quote" but has_many :quotes does not work as I have only one quote_id column (I suppose this is the problem). I see that i need to define a third class as quotebom_quote_id but cannot figure out how exactly!
Any help will be greatly appreciated!
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Profile < ActiveRecord::Base
has_many :images, :as => :imageable
end
class Article < ActiveRecord::Base
has_many :images, :as => :imageable
end
This is how we have made a single Image model and it is accessed by one or more than one model
Please refer this
Link
From what I can tell, you wish to create a database structure containing the models Quote and QuoteBom where a Quote has many QuoteBom and QuoteBom belongs to many Quotes.
That being the case, you will want to use a has_and_belongs_to_many association.
This will require adding to your models
class Quote < ActiveRecord::Base
has_and_belongs_to_many :quote_boms
end
class QuoteBom < ActiveRecord::Base
has_and_belongs_to_many :quotes
end
...and the following migration (assuming Quote and QuoteBom already exist)
class CreateQuotesAndQuoteBoms < ActiveRecord::Migration
def change
create_table :quote_quote_boms, id: false do |t|
t.belongs_to :quote, index: true
t.belongs_to :quote_bom, index: true
end
end
end
By having the associations above in the model and this table in your database, rails will automagically handle the associations between quote and quote_doms. As a result, you will also be able to access quote_dom.quotes which you said you weren't able to do in your question.
This is NOT a polymorphic association. A polymorphic association allows a model to belong to more than one type of other model in a single association.
Let's say you have two models Venue and Photo. Each Venue can have many Photos, but it can only have one FeaturedPhoto. Each Photo can be belong to many Venues and can be the FeaturedPhoto of more than one Venue too.
I already have the general has_and_belongs_to_many relationship set up and working through a join table with these models:
class Photo < ActiveRecord::Base
mount_uploader :image, PhotoUploader
has_and_belongs_to_many :venues
end
class Venue < ActiveRecord::Base
has_and_belongs_to_many :photos
end
To add the FeaturedPhoto, it seems like I would need to add a column called featured_photo_id to the Venue model and then set up a has_many, belongs_to association between the two. But I'm not sure where to add the foreign_key info. Is this right?
class Photo < ActiveRecord::Base
mount_uploader :image, PhotoUploader
has_and_belongs_to_many :venues
has_many :venues
end
class Venue < ActiveRecord::Base
has_and_belongs_to_many :photos
belongs_to :photo, foreign_key: "featured_photo_id", class_name: "Photo"
end
Or do I have to add foreign_key info to both models?
This can be achieved if you add a model for intermediate table PhotosVenue and add a boolean column is_featured in this intermediate table.
I created a demo app to do exactly what you want. Check this github repo
Hope this helps :)
has_many :through
I concur with SiriusROR - you need to use a has_many :through model, with an extra boolean attribute called featured:
#app/models/photo.rb
Class Photo < ActiveRecord::Base
has_many :photo_venues
has_many :venues, through: :venue_photos
end
#app/models/venue.rb
Class Venue < ActiveRecord::Base
has_many :photo_venues
has_many :photos, through: :venue_photos do
def featured
find_by featured: true
end
end
end
#app/models/photo_venue.rb
Class VenuePhoto < ActiveRecord::Base
belongs_to :photo
belongs_to :venue
end
--
Your schema for the :through model should be set up like this:
#photo_venues
id | photo_id | venue_id | featured | created_at | updated_at
--
This will allow you to call:
#venue.photos.featured # -> should bring back the single ActiveRecord object for the first featured photo in the collection
My models look something like this:
class User < ActiveRecord::Base
attr_accessible: :name
has_many :reviews
end
class Product < ActiveRecord::Base
attr_accessible: :name
has_many :reviews
end
class Review < ActiveRecord::Base
attr_accessible: :comment
belongs_to :user
belongs_to :product
validates :user_id, :presence => true
validates :product_id, :presence => true
end
I am trying to figure out what the best way is to create a new Review, given that :user_id and :product_id are not attr_accessible. Normally, I would just create the review through the association ( #user.reviews.create ) to set the :user_id automatically, but in this case I am unsure how to also set the product_id.
My understanding is that if I do #user.reviews.create(params), all non attr_accessible params will be ignored.
You can do:
#user.reviews.create(params[:new_review])
...or similar. You can also use nested attributes:
class User < ActiveRecord::Base
has_many :reviews
accepts_nested_attributes_for :reviews
...
See "Nested Attributes Examples" on http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html.
It seems you would like to implement a many-to-many relationship between a User and Product model, with a Review model serving as a join table to connect the two with an added comment string. This can be accomplished with a has many through association in Rails. Start by reading the Rails Guides on Associations.
When setting up your Review model, add foreign keys for the User and Product:
rails generate model review user_id:integer product_id:integer
And set up your associations as follows:
class User < ActiveRecord::Base
has_many :reviews
has_many :products, through: :reviews
end
class Product < ActiveRecord::Base
has_many :reviews
has_many :users, through: :reviews
end
class Review < ActiveRecord::Base
# has comment string attribute
belongs_to :user
belongs_to :product
end
This will allow you to make calls such as:
user.products << Product.first
user.reviews.first.comment = 'My first comment!'
Here's how you would create a review:
#user = current_user
product = Product.find(params[:id])
#user.reviews.create(product: product)