Qualcuno può dirmi cosa
send("#{Model.find...}")
è e fa?
Qualcuno può dirmi cosa
send("#{Model.find...}")
è e fa?
Risposte:
send
invia un messaggio a un'istanza di un oggetto e ai suoi antenati nella gerarchia di classi finché un metodo non reagisce (perché il suo nome corrisponde al primo argomento).
In pratica, quelle righe sono equivalenti:
1.send '+', 2
1.+(2)
1 + 2
Si noti che send
ignora i controlli di visibilità, in modo da poter chiamare anche metodi privati (utile per i test di unità).
Se non c'è davvero nessuna variabile prima dell'invio, significa che viene utilizzato l'Oggetto globale:
send :to_s # "main"
send :class # Object
send è un metodo ruby (senza rails) che consente di invocare un altro metodo per nome.
Dalla documentazione
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
Una delle funzionalità più utili che penso con il metodo .send è che può chiamare dinamicamente il metodo. Questo può farti risparmiare un sacco di digitazione. Uno degli usi più diffusi del metodo .send è l'assegnazione dinamica degli attributi. Per esempio:
class Car
attr_accessor :make, :model, :year
end
Per assegnare gli attributi regolarmente sarebbe necessario
c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"
O utilizzando il metodo .send:
c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")
Ma tutto può essere sostituito con il seguente:
Supponendo che la tua app Rails debba assegnare attributi alla tua classe di auto dall'input dell'utente, puoi farlo
c = Car.new()
params.each do |key, value|
c.send("#{key}=", value)
end
Un altro esempio, simile a https://stackoverflow.com/a/26193804/1897857 di Antonio Jha
è se hai bisogno di leggere gli attributi su un oggetto.
Ad esempio, se hai un array di stringhe, se provi a iterarle e chiamarle sul tuo oggetto, non funzionerà.
atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.a
end
# => NoMethodError: undefined method `a'
Tuttavia, puoi inserire send
le stringhe nell'oggetto:
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
è un altro modo per chiamare un metodo.
Questo è meglio illustrato da un esempio:
o = Object.new
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.to_s # => "#<Object:0x00005614d7a24fa3>"
Invia vite nella classe Object .
Il vantaggio di questo approccio è che puoi passare il metodo che desideri chiamare come parametro. Qui c'è un semplice esempio:
def dynamically_call_a_method(name)
o = Object.new
o.send name
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"
Puoi passare il metodo che vuoi essere chiamato. In questo caso siamo passati :to_s
. Questo può essere molto utile quando si esegue la metaprogrammazione di ruby, perché questo ci consente di chiamare diversi metodi in base alle nostre diverse esigenze.
Un altro caso d'uso per le visualizzazioni:
<%= link_to
send("first_part_of_path_#{some_dynamic_parameters}_end_path",
attr1, attr2), ....
%>
Permettere . di scrivere viste scalabili che lavorano con tutti i tipi di oggetti con:
render 'your_view_path', object: "my_object"