Czy ktoś może mi powiedzieć co
send("#{Model.find...}")
jest i robi?
Czy ktoś może mi powiedzieć co
send("#{Model.find...}")
jest i robi?
Odpowiedzi:
send wysyła komunikat do instancji obiektu i jego przodków w hierarchii klas, dopóki jakaś metoda nie zareaguje (ponieważ jej nazwa pasuje do pierwszego argumentu).
Praktycznie rzecz biorąc, te wiersze są równoważne:
1.send '+', 2
1.+(2)
1 + 2
Zauważ, że sendpomija sprawdzanie widoczności, więc możesz wywoływać również metody prywatne (przydatne do testowania jednostkowego).
Jeśli tak naprawdę nie ma zmiennej przed wysłaniem, oznacza to, że używany jest obiekt globalny:
send :to_s # "main"
send :class # Object
send jest metodą ruby (bez szyn) pozwalającą na wywołanie innej metody po nazwie.
Z dokumentacji
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
Myślę, że jedną z najbardziej przydatnych funkcji metody .send jest to, że może ona dynamicznie wywoływać metodę. Może to zaoszczędzić wiele pisania. Jednym z najpopularniejszych zastosowań metody .send jest dynamiczne przypisywanie atrybutów. Na przykład:
class Car
attr_accessor :make, :model, :year
end
Aby regularnie przypisywać atrybuty, należałoby to zrobić
c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"
Lub używając metody .send:
c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")
Ale to wszystko można zastąpić następującymi:
Zakładając, że aplikacja Rails musi przypisać atrybuty do klasy samochodu na podstawie danych wejściowych użytkownika, możesz to zrobić
c = Car.new()
params.each do |key, value|
c.send("#{key}=", value)
end
Inny przykład, podobny do https://stackoverflow.com/a/26193804/1897857 Antonio Jha
jest wtedy, gdy chcesz odczytać atrybuty obiektu.
Na przykład, jeśli masz tablicę ciągów, jeśli spróbujesz iterować przez nie i wywołać je na swoim obiekcie, to nie zadziała.
atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.a
end
# => NoMethodError: undefined method `a'
Możesz sendjednak napisać ciągi do obiektu:
atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.send(a)
end
# => Vandalay Project
# => A very important project
define_method: apidock.com/ruby/Module/define_method .
send to inny sposób na wywołanie metody.
Najlepiej ilustruje to przykład:
o = Object.new
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.to_s # => "#<Object:0x00005614d7a24fa3>"
Zaletą tego podejścia jest to, że jako parametr można przekazać metodę, którą chcesz wywołać. Oto prosty przykład:
def dynamically_call_a_method(name)
o = Object.new
o.send name
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"
Możesz przekazać metodę, którą chcesz wywołać. W tym przypadku przeszliśmy :to_s. Może to być bardzo przydatne przy metaprogramowaniu w języku ruby, ponieważ pozwala nam to wywoływać różne metody zgodnie z naszymi różnymi wymaganiami.
Inny przypadek użycia widoków:
<%= link_to
send("first_part_of_path_#{some_dynamic_parameters}_end_path",
attr1, attr2), ....
%>
Dopuszczać . możesz napisać skalowalny widok, który pracuje z wszelkiego rodzaju obiektami z:
render 'your_view_path', object: "my_object"