Как использовать API атрибутов внутри концерна в Rails? - PullRequest
0 голосов
/ 09 апреля 2019

У меня есть простая общая модель рельсов, которая выглядит следующим образом:

class Thing < ApplicationRecord
  attribute :foo, :integer
  include AConcern
end

И она включает в себя основную проблему, которая выглядит следующим образом ...

module AConcern
  extend ActiveSupport::Concern
end

Модель также имеет атрибутnamed: foo, используя атрибут api снизу:

https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html

Атрибут относится к концерну, поэтому каждый раз, когда я хочу использовать концерн, в каждой модели мне нужно определитьатрибут, а затем включить задачу.

Если я поместил декларацию атрибута внутри задачи следующим образом:

module AConcern
  extend ActiveSupport::Concern
  attribute :foo, :integer
end

Я получу следующую ошибку:

undefined method `attribute' for AConcern:Module

Как использовать определение атрибута в концерне, чтобы мне не приходилось объявлять его в каждой модели перед включением концерна?Спасибо

1 Ответ

2 голосов
/ 09 апреля 2019

Вы можете использовать ActiveSupport::Concern входящий в комплект крючок, например.

module AConcern
  extend ActiveSupport::Concern
  included do 
    attribute :foo, :integer
  end
end 

Тогда

class Thing < ApplicationRecord
  include AConcern
end

Проблема, с которой вы сейчас сталкиваетесь, заключается в том, что attribute вызывается в контексте вашего Module, но этот модуль не имеет доступа к этому методу (следовательно, NoMethodError).

Хук included запускается при вызове include, а хук запускается в контексте включающего Object (Thing в данном случае). Thing имеет метод attribute, и, таким образом, все работает, как ожидалось.

included блок из ActiveSupport::Concern по существу такой же, как (в чистом рубине)

module AConcern
  def self.included(base) 
    base.class_eval { attribute :foo, :integer } 
  end 
end
...