Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
420 views
in Technique[技术] by (71.8m points)

Ruby send method with rails associations

I have been messing about with making a sortable table module thing. I know some might exist but want to get experience doing this myself. I had the idea of have it like so:

SortedTable.new(ModelName, Hash_Of_Columns_And_Fields, ID)

example

SortedTable.new(Post, {"Title" => "title", "Body" => "body", "Last Comment" => "comment.last.title"}, params[:id])

I am planning to do something like:

def initialize(model, fields, id)
  data = {}
  model = model.capitalize.constantize
  model.find(id)
  fields.each do |column, field|
    data[column] = model.send(field)
  end
end

This works fine for title and body but when it comes to getting the Last Comment with comment.last.title it errors out. I have tried doing Post.send("comments.last.title") but says NoMethodError: undefined method 'comments.last.title' for #<Post:0x0000010331d220>

I know I can do Post.send("comments").send("last").send("title") and that works but I can not think of how to do that dynamically by taking the fields and spliting the on . then chaining the sends. Can anyone give me advice on how to do this? If I am doing this completely wrong also then please say or point me in the direction of code that does something similar. I am not a expert ruby developer but I am trying.

P.S The above code might not work as I am not at a computer with ruby/rails to test, but hopefully you get the concept.

Cheers

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

first and dirtiest solution is eval

fields.each do |column, field|
  data[column] = eval("#{model}.#{field}")
end

next solution little more functional

fields.each do |column, field|
  data[column] = field.split(".").inject(model){|obj, met| obj.send(met)}
end

PS

And your design is ugly

EDIT

The inject can be written more concisely as field.split('.').inject(model, :send). And I'd strongly discourage the eval way — unnecessary evals are one more case where you can slip up and allow arbitrary code execution, and they're also slow. (Also, I'm pretty sure that should just be eval("model.#{field}") — you don't want to interpolate the string value of model. Yet another example of how easy it is to slip up an eval expression.) – @Chuck


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...