Метод отправки Ruby с ассоциациями рельсов

Я возился с созданием сортируемого модуля таблицы. Я знаю, что некоторые могут существовать, но хочу получить опыт, делая это сам. У меня была идея сделать это так:

SortedTable.new(ModelName, Hash_Of_Columns_And_Fields, ID)

пример

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

Я планирую сделать что-то вроде:

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

Это хорошо работает для заголовка и тела, но когда дело доходит до получения Last Comment с comment.last.title это ошибки. Я пытался делать Post.send("comments.last.title") но говорит NoMethodError: undefined method 'comments.last.title' for #<Post:0x0000010331d220>

Я знаю, что могу сделать Post.send("comments").send("last").send("title") и это работает, но я не могу придумать, как сделать это динамически, взяв поля и разделив их на. затем приковывает цепочки Кто-нибудь может дать мне совет, как это сделать? Если я делаю это совершенно неправильно, то, пожалуйста, скажите или укажите мне направление кода, которое делает что-то подобное. Я не опытный разработчик ruby, но я пытаюсь.

PS Приведенный выше код может не работать, поскольку я не на компьютере с ruby ​​/ rails для тестирования, но, надеюсь, вы поняли концепцию.

ура

1 ответ

Решение

Первое и самое грязное решение eval

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

следующее решение немного более функционально

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

PS

И ваш дизайн уродлив

РЕДАКТИРОВАТЬ

Внедрение может быть написано более кратко, как field.split('.').inject(model, :send), И я бы сильно отговорил eval путь - ненужный evals Это еще один случай, когда вы можете ускользнуть и разрешить выполнение произвольного кода, и они также медленны. (Кроме того, я уверен, что это должно быть eval("model.#{field}") - вы не хотите интерполировать строковое значение model, Еще один пример того, как легко проскользнуть eval выражение.) - @Chuck

Другие вопросы по тегам