Rails associations has_many through ban/archive solution?

半腔热情 提交于 2019-12-08 06:40:22

问题


I'm new in Rails and am working on a problem. I have two tables:

Shoes and Socks

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

1) Using an additional column in table socks to represent the active sock

class Shoe < ActiveRecord::Base
  has_many :socks
end

class Sock < ActiveRecord::Base
  belongs_to :shoe
end

class CreateGettingDressed < ActiveRecord::Migration
  def change
    create_table :shoes do |t|
      t.string :size
      t.timestamps null: false
    end

    create_table :socks do |t|
      t.belongs_to :shoe, index:true
      t.string :pattern
      t.boolean :active
      t.timestamps null: false
    end
  end
end

This seems fairly simple, but cumbersome. I would search socks with shoe_id, and pull out the active_sock and return it's pattern. I think I would index [active_sock, shoe_id] in an array to speed it up.

2) Using an additional table to archive inactive socks

class Shoe < ActiveRecord::Base
  has_many :socks
  has_many :inactive_socks
end

class Sock < ActiveRecord::Base
  belongs_to :Shoe
end

class Inactive_sock < ActiveRecord::Base
  belongs_to :Shoe
end

class CreateGettingDressed < ActiveRecord::Migration
  def change
    create_table :shoes do |t|
      t.string :name
      t.timestamps null: false
    end

    create_table :socks do |t|
      t.belongs_to :shoe, index:true
      t.string :pattern
      t.timestamps null: false
    end


    create_table :inactive_socks do |t|
      t.belongs_to :shoe, index:true
      t.string :pattern
      t.timestamps null: false
    end
  end
end

This seems cumbersome as well, but when you are just dealing with active socks easy to use and fast. But when buying a new sock, I have to check the pattern with both tables.

3) Using a has_many :through relationship

class Shoe < ActiveRecord::Base
  has_many :active_socks
  has_many :socks, through: active_socks 
end

class Active_Sock < ActiveRecord::Base
  belongs_to :Shoe
  belongs_to :Sock
end

class Sock < ActiveRecord::Base
  has_many :active_socks
  has_many :shoes, through: active_socks
end

class CreateGettingDressed < ActiveRecord::Migration
  def change
    create_table :shoes do |t|
      t.string :name
      t.timestamps null: false
    end

    create_table :socks do |t|
      t.string :pattern
      t.timestamps null: false
   end

    create_table :active_socks do |t|
      t.belongs_to :shoe, index: true
      t.belongs_to :sock, index: true
      t.string :pattern
      t.boolean :active
      t.timestamps null: false
    end
  end
end

This seems like option 2, but I feel like I'm using Rails tools to make it less cumbersome. When I'm searching for patterns I'm just checking the socks table, when I'm searching for the one active_sock I'm just searching active_socks table.

I've read up on similar posts, and it seems options 1 and 2 are commonly used in closed_accounts, banning users, banning posts, archiving etc. Situations where you need to differentiate data that is only slightly different. The choice there seems to be look at what you need and choose the option 1 or 2 that best fits you.

My understanding for has_many through situations seems to be when you have a relationship and you need extra meta data you can use it. I think that fits this situation.

Did I set up option 1 correctly and am I right that indexing the array of [shoe_id and active] will give me a faster search? Is option 3 an appropriate use of has_many through? Would my explanation of option 3 work?


回答1:


What are your usage patterns? I'm guessing you just want to be able to find the active Sock given a Shoe, and if a given Sock is active or inactive. To quickly find the active Sock of a given Shoe, you merely need to give the Sock a foreign key to its Shoe with the belongs_to association.

class Sock < ActiveRecord::Base
  belongs_to :shoe
end

And 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

Now, you can just go to its owner Shoe and check if the Shoe's active sock is the current Sock or not. E.g.

def is_active
  owner_shoe.active_sock == self

Basically, associate them with foreign keys and you're good to go! P.S. you pluralized Socks but the Rails convention is to use singular for model names.

EDIT: You asked for a migration so here's one for the code above. Caveat: I haven't done migrations in a long time in Rails so something might be off.

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


来源:https://stackoverflow.com/questions/32756143/rails-associations-has-many-through-ban-archive-solution

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