最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ruby on rails - Custom method as ID - Stack Overflow

programmeradmin4浏览0评论

I have two models:

class Product
  belongs_to :storage_box
end

class StorageBox
  validates :key
            presence: true,
            uniqueness: { scope: %i[kind] }

  validates :kind
            presence: true
  def code
    "#{key}#{kind.to_s.rjust(4, '0')}"
  end
end

I would like to be able to set the storage_box relation based on the code method:

Product.new(storage_box: '150001')

How should I proceed to achieve this? I'm not sure if the Product should handle this (seems not "rails" to do it there) or to instruct the StorageBox how to find base on the code.

I have two models:

class Product
  belongs_to :storage_box
end

class StorageBox
  validates :key
            presence: true,
            uniqueness: { scope: %i[kind] }

  validates :kind
            presence: true
  def code
    "#{key}#{kind.to_s.rjust(4, '0')}"
  end
end

I would like to be able to set the storage_box relation based on the code method:

Product.new(storage_box: '150001')

How should I proceed to achieve this? I'm not sure if the Product should handle this (seems not "rails" to do it there) or to instruct the StorageBox how to find base on the code.

Share Improve this question asked 18 hours ago Daniel CostaDaniel Costa 2953 silver badges14 bronze badges 1
  • I really wouldn't recommend this. If you want to use a primary key that's not an auto-incrementing integer use a UUID or something else that's less likely to cause a collision. – max Commented 4 hours ago
Add a comment  | 

1 Answer 1

Reset to default 1

There are many ways you could code Product.new(storage_box: '150001'). For example you could probably overwrite the storage_box= method to detect a string input and generate a new StorageBox instance to replace the string. But I would strongly recommend you do not!

The problem with that approach is that you are making the standard ActiveRecord methods work in ways that they weren't designed to. In my experience that always causes unexpected consequencies later on. Also it will confuse the next developer who touches your code.

Instead I recommend you write a dedicated class method:

def self.new_in_storage_box(code)
  key = code[0..-5]
  kind = code[-4..-1]
  storage_box = StorageBox.find_or_create_by(key:, kind:)
  new(storage_box:)
end

Your call then becomes Product.new_in_storage_box('15001')

Even better, I'd suggest you move the breakdown of the storage box code to the storage box class. So:

class StorageBox
  def self.find_or_create_by_code(code)
    key = code[0..-5]
    kind = code[-4..-1]
    find_or_create_by(key:, kind:)
  end
  ...
end

class Product
  def self.new_in_storage_box(code)
    storage_box = StorageBox.find_or_create_by_code(code)
    new(storage_box:)
  end
  ...
end

That way your intension is clear and the new code will not interfere with the normal operation of the Product.new method.

发布评论

评论列表(0)

  1. 暂无评论