简体   繁体   English

仅当有has_many或has_one时,属地才有所有权

[英]belongs_to belongs_to association only no has_many or has_one

Can you have a belongs_to belongs_to relationship in Rails? 您可以在Rails中建立一个名为belongs_to belongs_to关系吗?

Search results gave me two results. 搜索 结果给了我两个结果。 The fact that I can't find very much info on the subject, seems to indicate that it shouldn't be done or is bad practice. 我找不到有关该主题的太多信息这一事实,似乎表明它不应该这样做,或者是不好的做法。

I asked yesterday about a has_many relationship, but thought because I couldn't find information on this, I would generate a question so it is easier for people to search for this in the future. 昨天我问了一个has_many关系,但由于无法找到有关此信息的信息,我会提出一个问题,以便将来人们更容易搜索此问题。 I'm paraphrasing another users answer (I hope this is ok). 我正在解释另一个用户的答案(我希望这样可以)。

A Shoe can have many Socks, but only one active Sock. 一只鞋子可以有许多袜子,但只有一只活动袜子。 Other Socks are inactive. 其他袜子无效。 All Socks are also unique with unique patterns. 所有袜子也都是独特的,具有独特的图案。 I want to make sure I don't have socks with the same pattern. 我想确保我没有相同图案的袜子。 I think I can do this three ways 我想我可以做到这三种方式

class Sock < ActiveRecord::Base
  belongs_to :shoe
end

To find out if a Sock is active or inactive, give its' owner shoe a reference to its active sock like so: 要确定袜子是处于活动状态还是非活动状态,请给其所有者的鞋子对其活动袜子的引用,如下所示:

class Shoe < ActiveRecord::Base
  belongs_to :sock
end

Go to its owner Shoe and check if the Shoe's active sock is the current Sock or not. 转到其所有者的鞋子,并检查鞋子的活动袜子是否为当前袜子。 Eg 例如

def is_active
  owner_shoe.active_sock == self

Associate them with foreign keys 将它们与外键关联

class CreateGettingDressed < ActiveRecord::Migration
  def change
    create_table :shoes do |t|
      t.belongs_to :active_sock, foreign_key: "sock_id"
      t.string :size
      t.timestamps null: false
    end

    create_table :socks do |t|
      t.belongs :owner_shoe, foreign_key: "shoe_id"
      t.string :pattern
    end
  end
end

In Rails, belongs_to is an indicator that the model has a foreign key . 在Rails中, belongs_to指示模型具有外键 For instance, if a sock belongs_to a shoe, then your sock table will have a shoe_id field. 例如,如果袜子belongs_to鞋子,那么您的袜子表将具有shoe_id字段。 There's a number of associations available to you, but having both shoes and socks use belongs_to sounds needlessly complex. 您可以使用多种关联 ,但是让鞋子和袜子都使用belongs_to听起来会很复杂。

The most straightforward solution is to change the language a little bit, and think of each sock as having one active shoe. 最直接的解决方案是稍微改变一下语言,并认为每只袜子都有一只活动鞋。 That way if you switch a sock to another shoe, then you don't have anything to tidy up on the shoe. 这样,如果将袜子换成另一只鞋,那么您就没有任何东西可以整理。 Your data's more likely to remain consistent that way. 这样您的数据更有可能保持一致。

class Shoe < ActiveRecord::Base
  has_one :sock
end

class Sock < ActiveRecord::Base
  belongs_to :shoe
end

You can now call shoe.sock to get a shoe's active sock, or sock.shoe to get a sock's shoe. 现在,您可以调用shoe.sock来获取鞋子的活动袜子,或者sock.shoe来获取袜子的鞋子。


Alternatively, maybe you'd like each shoe to have a dedicated pool of socks. 另外,也许您希望每双鞋子都有专用的袜子池。 We can extend our previous solution to support that, name our relationship active_sock to make things clearer, and use a validator to make sure that our sock is from the pool: 我们可以扩展先前的解决方案来支持该解决方案,将我们的关系命名为active_sock以使事情更清楚,并使用验证器来确保我们的sock来自池中:

class Shoe < ActiveRecord::Base
  has_many :socks
  has_one :active_sock, class_name: "Sock", foreign_key: "active_shoe_id"

  validates :active_sock_id, inclusion: { in: sock_ids }
end

class Sock < ActiveRecord::Base
  belongs_to :shoe

  def active?
    shoe.active_sock == self
  end
end

Now you can call shoe.socks to get all the available socks for a shoe, and shoe.active_sock to get the active sock. 现在,您可以拨打shoe.socks让所有的鞋子可用的袜子, shoe.active_sock获取活动袜子。 From the sock side, then sock.shoe returns which shoe "owns" this sock, and sock.active? 从袜子那边, sock.shoe返回该袜子“拥有”哪只鞋子,并且sock.active? returns whether this sock is currently active. 返回此袜子当前是否处于活动状态。

The problem you have is your two pieces of functionality are conflicting: 您遇到的问题是您的两个功能冲突:

A Shoe can have many Socks , but only one active Sock Shoe可以有很多Socks ,但只有一只活动Sock

You're looking to associate the two models on two different associations. 您正在将两个模型关联到两个不同的关联上。 Although this is simply done, I feel the way you're trying to do is is a little restricted. 尽管这只是简单的完成,但我觉得您尝试做的方式有点受限制。

Here's how I'd set up the base association: 这是我建立基本关联的方法:

#app/models/sock.rb
class Sock < ActiveRecord::Base
   #columns id | shoe_id | name | active (boolean) | created_at | updated_at
   belongs_to :shoe
end

#app/models/shoe.rb
class Shoe < ActiveRecord::Base
   #columns id | name | etc | created_at | updated_at
   has_many :socks
   scope :active, -> { where(active: true).first }
end

This will give you the ability to call: 这将使您能够调用:

@shoe = Shoe.find 1
@shoe.socks.active #-> first sock with "active" boolean as true

It will also negate the need to include an active? 它还将否定需要包括一个active? method in your sock model. sock模型中的方法。 You can call @shoe.socks.find(2).active? 您可以致电@shoe.socks.find(2).active? to get a response as to whether it's active or not. 获得有关它是否处于活动状态的响应。


Now, this should work pretty well for basic functionality. 现在,这对于基本功能应该可以很好地工作。

However, you mention several extensions: 但是,您提到了几个扩展:

if a Sock is active or inactive 袜子是active还是inactive

I want to make sure I don't have socks with the same pattern 我要确保我没有相同图案的袜子

This adds extra specifications which I'd tackle with a join model ( has_many :through ): 这增加了额外的规范,我将使用join模型( has_many :through )来解决:

#app/models/sock.rb
class Sock < ActiveRecord::Base
   has_many :shoe_socks
   has_many :shoes, through: :shoe_socks
end

#app/models/shoe_sock.rb
class ShoeSock < ActiveRecord::Base
   # columns id | shoe_id | sock_id | pattern_id | active | created_at | updated_at
   belongs_to :shoe
   belongs_to :sock
   belongs_to :pattern
end

#app/models/shoe.rb
class Shoe < ActiveRecord::Base
   has_many :shoe_socks
   has_many :socks, through: :shoe_socks, extend: ActiveSock
   scope :active, -> { where(active: true).first }
end

You can read more about the below code here : 您可以在此处阅读有关以下代码的更多信息:

#app/models/concerns/active_sock.rb
module ActiveSock

    #Load
    def load
      captions.each do |caption|
          proxy_association.target << active
      end
    end

    #Private
    private

    #Captions
    def captions
            return_array = []
            through_collection.each_with_index do |through,i|
                    associate = through.send(reflection_name)
                    associate.assign_attributes({active: items[i]})
                    return_array.concat Array.new(1).fill( associate )
            end
            return_array
    end

    #######################
    #      Variables      #
    #######################

    #Association
    def reflection_name
            proxy_association.source_reflection.name
    end

    #Foreign Key
    def through_source_key
            proxy_association.reflection.source_reflection.foreign_key
    end

    #Primary Key
    def through_primary_key
              proxy_association.reflection.through_reflection.active_record_primary_key
    end

    #Through Name
    def through_name
            proxy_association.reflection.through_reflection.name
    end

    #Through
    def through_collection
            proxy_association.owner.send through_name
    end

    #Captions
    def items
            through_collection.map(&:active)
    end

    #Target
    def target_collection
            #load_target
            proxy_association.target
    end

This setup will basically put all the "logic" into the join model. 此设置基本上会将所有“逻辑”放入联接模型。 IE you'll have a database of socks , one of shoes and a connecting DB with parings of both. 在IE中,您将拥有一个袜子数据库,一个鞋子数据库和一个具有两者配对的连接数据库。

This will still permit you to call @shoe.socks.active but without having to degrade the data integrity in your data models. 这仍然允许您调用@shoe.socks.active但不必降低数据模型中的数据完整性。

I have also added some code I wrote a while back - which gives you the ability to access attributes from the join model. 我还添加了一段时间后写的一些代码-使您能够从连接模型访问属性。 It uses the proxy_association object in ActiveRecord, so it doesn't invoke any more SQL. 它使用ActiveRecord中的proxy_association对象,因此不再调用任何SQL。

This added code will append the active? 此添加的代码将追加active? attribute to any associative Sock objects. 属性分配给任何关联的Sock对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM