Jak mogę nadpisać metodę pobierającą w modelu ActiveRecord?

98

Próbuję nadpisać metodę pobierającą dla modelu ActiveRecord. Mam atrybut o nazwie namew modelu Categoryi chciałbym móc zrobić coś takiego:

def name
  name_trans || name
end

Jeśli name_transatrybut nie jest nil, zwróć go, w przeciwnym razie zwróć nameatrybut. Jak bym to zrobił?

Należy to wtedy nazwać normalnie w ten sposób:

@category.name
oyvindhauge
źródło

Odpowiedzi:

123

Przewodnik po stylach szyn zaleca używanie self[:attr]over read_attribute(:attr).

Możesz go używać w ten sposób:

def name
  name_trans || self[:name]
end
Wonsup Lee
źródło
Dlaczego to jest lepsze? Nie umieszczaj linków do innych witryn, dołącz tutaj odpowiednie fragmenty. Linki mogą stać się nieważne
JamesT
2
Aby uzyskać więcej kontekstu, zobacz tutaj: github.com/bbatsov/rails-style-guide/issues/155
mimsugara
98

Aktualizacja: Preferowaną metodą według Przewodnika po stylach Rails jest użycie self[:name]zamiast read_attributei write_attribute. Zachęcam do pominięcia mojej odpowiedzi i zamiast tego wolę .


Możesz to zrobić dokładnie w ten sposób, z tym wyjątkiem, że musisz użyć, read_attributeaby faktycznie pobrać wartość atrybutu name i uniknąć rekurencyjnego wywołania namemetody:

def name 
  name_trans || read_attribute(:name)
end
meagar
źródło
2
Masz jakiś pomysł, dlaczego Rubocop woli self[:name]więcej read_attribute[:name]?
Zack Xu
18

Chciałbym dodać kolejną opcję nadpisywania metody gettera, która jest po prostu super.

def name
  name_trans || super
end

działa to nie tylko na metodzie pobierającej atrybuty, ale także na metodach pobierających asocjacje , także。

lei liu
źródło
1
To właśnie zalecają obecnie przewodniki Rails, dla getterów ORAZ seterów: api.rubyonrails.org/classes/ActiveRecord/ ...
sandre89
5

Zastępowanie metody pobierającej i używanie read_attributenie działa w przypadku skojarzeń, ale alias_method_chainzamiast tego można użyć .

def name_with_override
  name_trans || name_without_override
end

alias_method_chain :name, :override
Patrick Oscity
źródło
Czy możesz podać dobry przykład ...?
Arup Rakshit
Dobrze. Właśnie zobaczyłem dokumentację . Jeśli teraz namewywołam obiekt modelu, który zostanie wywołany - name_with_overrideczy name_without_override?
Arup Rakshit
1
nameteraz zadzwoni name_with_override. Jeśli z jakiegoś powodu chcesz wywołać oryginalną metodę, możesz wywołać name_without_override.
Patrick Oscity
O, rozumiem… Dzięki za odpowiedzi //
Arup Rakshit,
2

Jeśli używasz atrybutów sklepu, takich jak ten

store :settings, accessors: [:volume_adjustment] 

lub używając klejnotów, takich jak link do klejnotów hstore_accessor

Skończyło się na użyciu storemetody na modelu, a następnie, aby zastąpić metodę, której nie możesz użyć self.read_attribute, musisz zamiast tego użyć super:

def partner_percentage
  super.to_i || 10
end
onemanstartup
źródło
0

Jeśli ktoś chce zaktualizować wartość after name_transw metodzie getter, możesz użyć 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
źródło
0

Możesz użyć metody read_attribute Railsów. Dokumenty Rails

Rajat Bansal
źródło
chociaż ten link może odpowiedzieć na pytanie, odpowiedzi na same łącza nie są dozwolone w SO, proszę dodać kontekst do odpowiedzi z tego, co znajduje się za tym łączem. Dzięki! :)
AJT82