0

I'm writing a simple page that will help me view the sync status of my sites custom gallery compared to my Flickr account.

I have a simple loop that iterates over a response from the Flickr API:

<% for collection in @flickr_hierarchy %>
  <%= traverse_collection(collection, 0) %>
<% end %>

traverse_collection is a Rails helper method as so:

module GalleryHelper

  def traverse_collection(collection, parent)
    parent = parent == 0 ? 0 : parent["id"]

    content_tag(:tr) do
      content_tag(:td, 'Collection')

      collectionLocal = Collection.where(flickr_id: collection.id).first

      if collectionLocal != nil
        content_tag(:td, 'Yes')
      else
        content_tag(:td, 'No')
      end
      content_tag(:td, '&nbsp;')
      content_tag(:td, '&nbsp;')
      content_tag(:td, collection.title)
      content_tag(:td, collection.id)
      content_tag(:td, parent.to_s)
      content_tag(:td, 'N/A')
      content_tag(:td) do
        if collectionLocal != nil
          button_to('Add all Sets', admin_add_all_sets_for_collection_path(flickr_collection_id: collection.id))
          button_to('Delete Collection', admin_delete_collection_path(flickr_collection_id: collection.id))
        else
          button_to('Add Collection', admin_add_collection_path(flickr_collection_id: collection.id, flickr_parent_collection_id: parent.to_s))
          button_to('Add Collection and Sets', admin_add_all_sets_for_collection_path(flickr_collection_id: collection.id, flickr_parent_collection_id: parent.to_s))
        end
      end
    end
  end

end

Unfortunately i've found out that there is no nice or non-messy code way to get the generated HTML to be output on my page.

Is there a good way to do this or should I be taking a different approach. Any ideas?

Thanks, Neil

5
  • Could you explain the problem? Are you trying to take the HTML logic out of the helper? Commented Mar 2, 2015 at 17:12
  • @kendotwill I can't get the generated HTML to be output when I run that helper method from my view. Commented Mar 2, 2015 at 17:15
  • Are you trying to generate the HTML after the page has already been loaded? Commented Mar 2, 2015 at 17:33
  • Can you provide more code, the controller? Commented Mar 2, 2015 at 17:55
  • @kendotwill No code is being generated after the page has loaded. There's no need for me to post the controller code. I have an var called @flickr_hierarchy. For each item of it I want to run that helper method which should spit out a chunk of HTML for the page to display. The display does not happen. I am assuming the HTML is being generated but I don;t know how to get it to output onto my page. Commented Mar 2, 2015 at 17:58

3 Answers 3

1
+50

You should move the assembly of the HTML out of your helper and into a partial. Create a file app/views/gallery/_row.html.erb (you can name it whatever you want, but make sure the file starts with an underscore) and put your HTML there, like this:

<tr>
  <td>Collection</td>
  <td><%= collection_local.present? ? "Yes" : "No" %></td>
  <td>&nbsp;</td>
  <td>&nbsp;</td>
  <td><%= collection.title %></td>
  <td><%= collection.id %></td>
  <td><%= parent %></td>
  <td>N/A</td>
  <td>
    <% if collection_local.present? %>
      <%= button_to(
            "Add all Sets", 
            admin_add_all_sets_for_collection_path(flickr_collection_id: collection.id)
            ) %>
      <%= button_to(
            "Delete Collection",
            admin_delete_collection_path(flickr_collection_id: collection.id)
            ) %>
    <% else %>
      <%= button_to(
            "Add Collection", 
            admin_add_collection_path(
              flickr_collection_id: collection.id, 
              flickr_parent_collection_id: parent.to_s
            )) %>
      <%= button_to(
            "Add Collection and Sets",
            admin_add_all_sets_for_collection_path(
              flickr_collection_id: collection.id, 
              flickr_parent_collection_id: parent.to_s
            )) %>
    <% end %>
  </td>
</tr>

Now all your helper has to do is call render with the name of the partial and the "locals" (variables) that your partial needs. The name in this case is gallery/row (filename without the underscore and extension), and the variables that the partial needs are: collection, collection_local, and parent. Therefore the render call would look like this:

module GalleryHelper

  def traverse_collection(collection, parent)
    parent = parent == 0 ? 0 : parent["id"]
    collection_local = Collection.where(flickr_id: collection.id).first

    render(
      partial: "gallery/row",
      locals: {
        collection: collection,
        collection_local: collection_local,
        parent: parent
      })
  end
end

Does that help?

There is more information about how to use partials in the official Ruby on Rails Guides.

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

2 Comments

That makes a lot of sense! I shall give that a go hopefully this evening when I get time. Thanks. I shall report back with how I get on.
This is perfect. Thanks for helping me see where I should have separated the concerns and keeping my code more agile and tidy!
1

You can use render in your helper method.

Please see How to render a view/partial in a helper w/o the layout?

Just wrap the template with your business/presentation logic in a helper method, prepare your scope and let the rendering engine do the rendering.

Does that help?

UPDATE

You can call practically everything in your helper method including render, which will instruct Rails engine to render any view/partial into request response

This is the helper implementation

# app/helpers/application_helper.rb
module ApplicationHelper
  def hello()
    # Prepare your model into locals, which will be passed to your partial
    # template
    render partial: 'shared/hello', locals: {text: 'world'}
  end
end

This is the partial template used in helper method

<!-- views/shared/_hello.html.erb -->
<div>hello <%= text %></div>

This is the main controller view orchestrating the request

<!-- views/welcome/index.html.erb -->
<h1>Test</h1>
<%= hello %>

2 Comments

Thanks for answering but i'm confused as how to use this to get it to work? Could you expand further in the context of my original question?
Please see my update. This should clarify your problem
0

You have to add a plus sign + at the end of each content_tag and maybe the button_to. Otherwise only the last content_tag will get created.

module GalleryHelper

  def traverse_collection(collection, parent)
    parent = parent == 0 ? 0 : parent["id"]

    collectionLocal = Collection.where(flickr_id: collection.id).first

    content_tag(:tr) do
      content_tag(:td, 'Collection') +

      content_tag(:td, (collectionLocal != nil) ? 'Yes' : 'No' ) +
      content_tag(:td, '&nbsp;') + 
      content_tag(:td, '&nbsp;') +
      content_tag(:td, collection.title) +
      content_tag(:td, collection.id) +
      content_tag(:td, parent.to_s) +
      content_tag(:td, 'N/A') +
      content_tag(:td) do
        if collectionLocal != nil
          button_to('Add all Sets', admin_add_all_sets_for_collection_path(flickr_collection_id: collection.id)) +
          button_to('Delete Collection', admin_delete_collection_path(flickr_collection_id: collection.id))
        else
          button_to('Add Collection', admin_add_collection_path(flickr_collection_id: collection.id, flickr_parent_collection_id: parent.to_s)) +
          button_to('Add Collection and Sets', admin_add_all_sets_for_collection_path(flickr_collection_id: collection.id, flickr_parent_collection_id: parent.to_s))
        end
      end
    end
  end
end

Rails- nested content_tag

2 Comments

This makes no difference what so ever.
@rctneil I tested it with the assumption that @flickr_hierarchy is not nil. If you view the source in the browser after after loading the page and you don't see an empty tr <tr></tr> then you function is not being called at all. I would start by debugging if your for is being executed. You will need a + at the end of your content_tags if you want to fix your current code.

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.