0

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

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

2 Comments

Hey, thanks for the quick reply. I thought my approach was going to be ugly :) Still learning. Any advice would be appreciated. Thanks for those solutions however!
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.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.