nullnullnull
nullnullnull

Reputation: 8189

Rails: Creating HTML in a Model

I have a Publication model with a has_many relationship to Contributors. In the model, I have a method that's meant to create an html-ready by line:

def authors
  authors = []
  Contributor.where(:publication_id => self.id).each do |author|
    authors << "link_to "+author.name+", Contributor.find("+author.id.to_s+")"
  end
  authors.to_sentence
end

In my view, I have the following line:

by <%= @publication.authors %>

But instead of rendering links, it renders the raw code, such as:

by link_to B, Contributor.find(1)

I've tried patching this by adding .html_safe to the end of @publication.authors, but to no avail. Is there a better way to transfer these links from the model to the view?

Upvotes: 0

Views: 120

Answers (2)

user684934
user684934

Reputation:

You're pushing strings into your authors array. It looks like valid code, so running eval on it should work. (Actually author.name will probably evaluate as an undefined symbol, so scratch that.)

A better way would be to use a has_many :authors, :model => 'Contributor' relationship on your Publication model, and you can bring up your array of Contributor objects by simply calling

@publication.authors

You'd want to iterate over these in your view like so:

<% @publication.authors.each do |author| %>
  <%= link_to author.name, author %>
<% end %>

Note also that if you're displaying multiple Publication objects in a view this way, you'll want to use Publication.includes(:authors) in your controller when you're retrieving them to avoid the "N+1" problem.

Now, three lines of code doesn't seem very expensive to repeat, but there are ways to DRY that without violating the MVC pattern and cluttering your model:

  • Place the code to print a publication's authors into a partial, and call the partial as needed.
  • Place the code into a helper, include the helper and call the method as needed.

Here's a snippet from the source for to_sentence (you can adapt it for your needs, I think):

case length
  when 0
    ""
  when 1
    self[0].to_s.dup
  when 2
    "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
  else
    "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
end

The full source can be found here.

Upvotes: 3

Arane
Arane

Reputation: 21

It looks like you are trying to use haml syntax in your line. Maybe instead of using link_to, use an html hyperlink tag itself?

That being said, why are you having a model return html?

Edit: bdares answered already with what I was trying to say

Upvotes: 2

Related Questions