Как я могу перезаписать метод получения в модели ActiveRecord?

99

Я пытаюсь перезаписать метод получения для модели ActiveRecord. У меня есть атрибут, вызываемый nameв модели Category, и я хотел бы сделать что-то вроде этого:

def name
  name_trans || name
end

Если name_transатрибут не равен нулю, вернуть его, иначе вернуть nameатрибут. Как бы я это сделал?

Затем это следует обычно вызывать следующим образом:

@category.name
Oyvindhauge
источник

Ответы:

125

Руководство по стилю Rails рекомендует использовать self[:attr]over read_attribute(:attr).

Вы можете использовать это так:

def name
  name_trans || self[:name]
end
Вонсуп Ли
источник
Почему лучше? Не делайте ссылки на другие сайты, включите сюда соответствующие фрагменты. Ссылки могут стать недействительными
JamesT
2
Дополнительную информацию см. Здесь: github.com/bbatsov/rails-style-guide/issues/155
mimsugara
98

Обновление: согласно Руководству по стилю Rails предпочтительным методом является использование self[:name]вместо read_attributeи write_attribute. Я бы посоветовал вам пропустить мой ответ и вместо этого предпочесть этот .


Вы можете сделать это точно так же, за исключением того, что вам нужно использовать read_attributeдля фактического получения значения атрибута name и избежать рекурсивного вызова nameметода:

def name 
  name_trans || read_attribute(:name)
end
user229044
источник
2
Любая идея , почему Rubocop предпочитает self[:name]более read_attribute[:name]?
Zack Xu
18

Я хотел бы добавить еще один вариант перезаписи метода получения, который просто супер.

def name
  name_trans || super
end

это работает не только с методом получения атрибутов, но и с методами получения ассоциаций , тоже。

лей Лю
источник
1
Это то, что в настоящее время рекомендуют руководства по Rails для геттеров И сеттеров: api.rubyonrails.org/classes/ActiveRecord/…
sandre89
5

Переопределение получателя и использования read_attributeне работает для ассоциаций, но вы можете использовать alias_method_chainвместо этого.

def name_with_override
  name_trans || name_without_override
end

alias_method_chain :name, :override
Патрик Оссити
источник
Можете привести хороший пример ...?
Аруп Ракшит
Хорошо. Я только что видел доко . Теперь, если я вызываю nameобъект модели, какой из них будет вызван - name_with_overrideили name_without_override?
Аруп Ракшит
1
nameсейчас буду звонить name_with_override. Если вы по какой-то причине хотите вызвать исходный метод, вы можете вызвать name_without_override.
Патрик Оссити,
Понятно
2

Если вы используете такие атрибуты магазина

store :settings, accessors: [:volume_adjustment] 

или используя драгоценные камни, такие как ссылка на драгоценный hstore_accessor камень

Итак, вы закончили использовать storeметод в модели, а затем, чтобы переопределить тот метод, который вы не можете использовать self.read_attribute, вы должны использовать вместо этого superвот так:

def partner_percentage
  super.to_i || 10
end
onemanstartup
источник
0

Если кто-то хочет обновить значение после name_transв методе получения, вы можете использовать self [: name] =.

def name
  self[:name] = name_trans || self[:name]
  # don't do this, it will cause endless loop
  # update(name: name_trans)
end
Fangxing
источник
0

Вы можете использовать метод read_attribute Rails. Документы по Rails

Раджат Бансал
источник
Хотя эта ссылка может ответить на вопрос, ответы только по ссылкам не разрешены в SO, пожалуйста, добавьте контекст к вашему ответу из того, что за этой ссылкой. Спасибо! :)
AJT82