2 different Model share 1 unique Photo Model - ruby-on-rails

Hello Rails Community !
I don't know how to structure my different models.
I have 2 differents models : cars and house
Theses models can have multiple photos.
My questions are :
Is it possible to use 1 photo model for the cars and house or I need to create 1 cars_photos model and 1 house_photos model
If it's possible, how can I generate my Photo model ?
=> Option 1
rails g model Photo name:string, description:text car:references house:references
Car.rb
has_many :photos
House.rb
has_many :photos
Photo.rb
belongs_to :car
belongs_to :house
The problem with this option is that a photo will have to be linked with a car AND with a house. Witch is not good.
=> I want a photo be linked with a car OR with a house
I don't know how to proceed...
Thx !

This is almost the exact prototypical polymorphic association from the Rails guides
$ rails g model Photo name:string description:text imageable:references{polymorphic}:index
Produces this migration file
class CreatePhotos < ActiveRecord::Migration[5.1]
def change
create_table :photos do |t|
t.string :name
t.text :description
t.references :imageable, polymorphic: true
t.timestamps
end
end
end
t.references :imageable, polymorphic: true is going to give you two columns on your photos table: imageable_id:integer which will be the id column of the associated object, and imageable_type:string which will be the stringified class name of the associated object. This allows photos to interface with and belong to any model on one association.
Then your models should look like this
class Photo < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
class Car < ApplicationRecord
has_many :photos, as: :imageable
end
class House < ApplicationRecord
has_many :photos, as: :imageable
end
You can add a Photo to a Car with Car.find(params[:car_id]).photos.create and assign a Car to a Photo with Photo.new imageable: Car.find(params[:car_id])

Yes, you can reuse photos for both cars and house.
There are two major gems
for photo uploading: paperclip and carrierwave.
Have a look at them before you continue with your modeling!

Related

Has_many of different models association in Rails

I have a few different models which I would like to add multiple images to.
I have an image model with belongs_to associations set up to the different owning models (each of these owning models has has_many :images defined).
I would like to know what's the appropriate migration I should create in order to add an image_ids column to each of owning models.
I assume something like this...
rails g migration AddImagesToBusinesses images businesses image_ids:integer
However, I'm confused as I believe that you can only make one association this way and it would need to be completed by adding a column to the images table to identify the id of the model it belongs to (here there are a few different models).
Thank you for your help.
As you concern about relationship of image to other model. You should try polymorphic associations like this.
Generate the Image model:
class CreateImages < ActiveRecord::Migration
def change
create_table :images do |t|
t.string :file_id
t.boolean :featured
t.references :imageable, polymorphic: true, index: true
t.timestamps null: false
end
end
end
Update the Image model:
class Image < ActiveRecord::Base
attachment :file
belongs_to :imageable, polymorphic: true
end
Add association to other models like this
class Model < ActiveRecord::Base
has_many :images, as: :imageable, dependent: :destroy
accepts_attachments_for :images, attachment: :file
end
For more details you Ruby on Rails Guide.
I think you need Polymorphic associations.
See documentaions here.

Model that belongs to one of two parents

I'm trying to decide on the best relationship structure for three models I have in a Rails app.
The models are candidate, an employer, and a video.
Sometimes a video will belong to an employer, other times a candidate. Because of this I am loathe to put foreign keys for both employer and candidate on a video, because it feels wrong that one will always be nil.
The problem with the code below is that the video will not have many candidates, but I can't do a through relationship with belongs_to. What is a better way?
class Video < ActiveRecord::Base
has_many :video_candidates
has_many :candidates, :through => :video_candidates
end
class Candidate < ActiveRecord::Base
has_many :video_candidates
has_many :videos, :through => :video_candidates
end
class VideoCandidate < ActiveRecord::Base
belongs_to :candidate
belongs_to :vieo
end
Edit: Polymorphic association is the way to go. I'm going to put my solution below. Hope this helps someone.
class Video < ActiveRecord
belongs_to :watchable, polymorphic: true
end
class Candidate < ActiveRecord::Base
has_many :videos, as: :watchable
end
class Employer < ActiveRecord::Base
has_many :videos, as: :watchable
end
And the migration
class CreateVideos < ActiveRecord::Migration[5.0]
def change
create_table :videos do |t|
t.string :title
t.belongs_to :watchable, polymorphic: true
t.timestamps
end
add_index :videos, [:watchable_id, :watchable_type]
end
end
This is an ideal case to go for polymorphic association
Also refer Railscast episode

change type in polymorphic association in rails

I am new to rails and I'm using rails Polymorphic association and I ran into a problem
I have two models EmployeeTable and ProductTable. Both have some picture in Picture Model
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
class EmployeeTable < ActiveRecord::Base
has_many :pictures, as: :imageable
end
class ProductTable < ActiveRecord::Base
has_many :pictures, as: :imageable
end
there are two column in Picture imagable_id and imagable_type. When I create an entry in table it stores imagable_type as either "EmployeeTable" or "ProductTable". Can I change these name to any different Names like "employee" and "product".
Thanks in advance
To retreive the image_type without with table, you can add this method in your model. Changing the assosiated model name while saving will cause issues while querying
def neat_imageable_type
self.imageable_type.gsub("Table", "").downcase
end

Multiple Images for Multiple Models - Paperclip, Rails

I have four models, let's call them Cars and Houses. Users can have multiple cars, and multiple houses. Cars and Houses belong to Users. I'd like users to be able to upload multiple photos of their cars, and multiple photos of their houses, and from what I've read this means creating a new model called 'Photos'. Is it possible for two different models to both have_many Photos, and for Photos to belong_to more than one model? I'm using Ruby 2.0.0 and Rails 4.
Sketch / PseudoRuby
User
has_many :cars
has_many :houses
Car
belongs_to :user
has_many :photos
House
belongs_to :user
has_many :photos
Photo
belongs_to :car, :house
Is this relationship ok? I wasn't sure if I had to make separate models for the photos of Car and House.
From a Rails standpoint, yes you can do it. The belongs_to association tells Rails to keep the foreign_key in the Photo model. So in your example, your photos table will have 2 foreign keys :
car_id which will point to the associated car id (primary key) from the cars table.
house_id which will point to the associated house id (primary key) from the house table.
Now, from the paperclip standpoint, you can have as many photos for a particular model as you want. But, in order to have the same Photo model associated to both House and Car, you need to use polymorphic association.
Your model will be similar to this :
class Photo < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
has_attached_file :photo, styles: {}
end
class Car < ActiveRecord::Base
has_many :photos, as: :imageable
end
class House < ActiveRecord::Base
has_many :photos, as: :imageable
end
You can get more information about polymorphic associations here: http://guides.rubyonrails.org/association_basics.html

Creating an auto-updating list in Rails

I have three relevant models:
class InventoryItem < ActiveRecord::Base
belongs_to :item, :foreign_key => :item_id
belongs_to :vendor
has_many :shopping_list_items
class ShoppingList < ActiveRecord::Base
has_many :shopping_list_items
belongs_to :user
end
class ShoppingListItem < ActiveRecord::Base
belongs_to :shopping_list
belongs_to :inventory_item
end
What I am trying to do is create a sidebar shopping list that will autoupdate ShoppingListItem attributes (specifically price) when a respective attribute is changed in the InventoryItem table (again, price). My thinking was to have these three classes and map ShoppingListItems directly to InventoryItems, but I'm unsure of how to proceed with that. Alternatively, is it possible to do away with the ShoppingListItem class entirely and make ShoppingList be a collection of InventoryItems specified by the user? Any input is much appreciated. Thanks in advance!
To redo my comments as a real answer, yes, it is possible to forego the ShoppingListItem model in this case, as long as you don't need to attach any data to that model itself (e.g. the time the item was added to the list). You could link your models as follows with a has_and_belongs_to_many association:
class InventoryItem < ActiveRecord::Base
belongs_to :item
belongs_to :vendor
has_and_belongs_to_many :shopping_lists
end
class ShoppingList < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :inventory_items
end
This will allow you to assign an array of inventory items to the inventory_items attribute of a shopping list, and Rails will create or delete the necessary join records automatically. More information from the Rails guides. Note that you'll still need a join table in your schema -- there just isn't a model associated with it. In your case, the migration might look like this:
create_table :inventory_items_shopping_lists, id: false do |t|
t.references :inventory_item
t.references :shopping_list
end
add_index :inventory_items_shopping_lists, :inventory_item_id
add_index :inventory_items_shopping_lists, :shopping_list_id
add_index :inventory_items_shopping_lists, [:inventory_item_id, :shopping_list_id], unique: true
Note that in order for Rails to auto-detect the table, its name should be the combined plural forms of both models in alphabetical order. Otherwise you need to specify the table name using the join_table option when defining the association.

Resources