Ruby on Rails named class property of model

泄露秘密 提交于 2020-01-25 10:10:22

问题


I have two classes Product and user which have a has_many relationship with a polymorphic type as such.

class User < ActiveRecord::Base
  has_many :pictures, as: :imageable
end

class Product < ActiveRecord::Base
  has_many :pictures, as: :imageable
end

class Picture < ActiveRecord::Base
   belongs_to :imageable, polymorphic: true
end

I want to also add a new property to the user models of profile_picture so @user.profile_picture will return a picture object. how can this be achieved? In particular the migration to add the foreign key to users.

Edit: I've updated the user model as such

has_one :profile_picture, class_name: "Picture", foreign_key: "profile_picture_id"

and added the following migration

add_column :users, :profile_picture_id, :integer

however i dont appear to be able to set the profile picture if someone could explain what exactly i am doing wrong it would be appreciated. thanks!


回答1:


There is no direct way to achieve this when using associations properly.

The data structure is wrong. You are trying to associate one and the same model in two different ways. And the problem is: these two ways interfere with each other.

You are effectively trying to store different types of objects using the same type. A direct way (suggested in another answer) would leave you with no way to determine which are simply User's pictures and what is his profile_picture among them. So any possible solution would require adding a way to distinguish a profile_picture.

Just yesterday I wrote an example on how to use "single table inheritance". It actually fits well here, you need two similar data constructs to behave in different ways. To make it work, you will need two things:

  1. Add STI support to pictures table:
    rails g migration AddTypeToPictures type:string:index
    ...and make sure you add a type column of type string with an index on it.

  2. rails g model ProfilePicture --no-migration --parent=Picture
    This class will be created empty, but will inherit everything from Picture, so it should stay empty in many cases.

Then just a simple association should work on any class:

has_one :profile_picture, as: :imageable

Let's assume we added this to User. Then the search criteria to find a User's profile picture will be:

  • type is "ProfilePicture"
  • imageable_type is "User"
  • imageable_id is equal to id of the user in question

Searches have become cumbersome, right? Well, this should work, but I don't recommend all this, it has implications and alternatives:

  • Whatever database column you decide to add to ProfilePicture, it will have to be added to Picture even if it's not used: they are stored in the same table.
    Solution: making ProfilePicture a full-fledged model: make a table for it, make it inherit ActiveRecord::Base.
  • Fetching a user's profile picture will require an extra database query with three (wow!) different criteria.
    Solution (recommended): placing a profile picture inside a corresponding model the same way it's done for Picture: this will require no extra queries to fetch a profile picture at all.



回答2:


class User < ActiveRecord::Base
  has_many :pictures
  has_one :profile_picture, :class_name => "Picture"
end

class Product < ActiveRecord::Base
  has_many :pictures
end

class Picture < ActiveRecord::Base
   belongs_to :imageable, polymorphic: true
end


来源:https://stackoverflow.com/questions/25596068/ruby-on-rails-named-class-property-of-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!