Displaying action partial on index page - object id doesn't

This problem is a continuation of an earlier thread “Partial doesn’t
yet have object” but I don’t think as many people saw it because my
question came up in a reply.

  • I’m building an store app that include a product catalog, details
    page, and cart.
  • I’m attempting to put them in the same layout using partials.
  • Product catalog is the index action of the store controller

Clicking on the product in the catalog invokes the “view_details”
action, which is fine if it not a partial (i.e. path in the browser is
/store/view_details/5). The problem is, according to my understanding
so far of partials, the action in “view_details” must “redirect_to
:action => :index”. Because of that redirect, it appears as though the
selection doesn’t persist and therefore my “view_details” (i.e. the
currently selected item) never displays.

So I’m starting to think that I have to store the current product
selected in the session by way of something like a “Basket” (more
temporary than a cart? good names are welcome) model.

Does that makes sense? Or is there a better way to make my selection
persist so I can display the catalog, deatails and cart all on the same
page?

Brandon Wright wrote:

This problem is a continuation of an earlier thread “Partial doesn’t
yet have object” but I don’t think as many people saw it because my
question came up in a reply.

  • I’m building an store app that include a product catalog, details
    page, and cart.
  • I’m attempting to put them in the same layout using partials.
  • Product catalog is the index action of the store controller

Clicking on the product in the catalog invokes the “view_details”
action, which is fine if it not a partial (i.e. path in the browser is
/store/view_details/5). The problem is, according to my understanding
so far of partials, the action in “view_details” must “redirect_to
:action => :index”. Because of that redirect, it appears as though the
selection doesn’t persist and therefore my “view_details” (i.e. the
currently selected item) never displays.

So I’m starting to think that I have to store the current product
selected in the session by way of something like a “Basket” (more
temporary than a cart? good names are welcome) model.

Does that makes sense? Or is there a better way to make my selection
persist so I can display the catalog, deatails and cart all on the same
page?

You could use the flash to save the curent object for one request, and
its cleared automatically after that:

def view_details
flash[:product_id] = params[:id]
redirect_to :action => ‘index’
end
def index
if flash[:product_id]
@product = Product.find(flash[:product_id])
end
end

Or you could use ajax to insert the partial into your index page.

Or, most simple of all, simply send people to a page wit info about the
product, without redirecting then back to the index page. The URLs and
navigation will be much simpler and cleaner this way.

(Yes, I’m this far behind reading the list mail, but I wanted to reply
since I may still have something to add.)

I think the main problem you have right now is a misunderstanding of how
layouts work.

Let’s first assume your controller is named store_controller.rb.
Instead of using a partial, let your method render it’s default
template. In the case of the view_details method in
store_controller.rb, this would be app/views/store/view_details.rhtml.
Rails will first render this template, save the output and then look for
an optional layout for the current controller (since layouts are
controller-specific).

Rails looks for the layout in the following order (see section 17.9 in
Agile Web D. with Rails or section 22.9 in the second edition.)

o Layout specified explicitly in a render command
o Layout specified in the current controller's "layout" command
o A layout named after the current controller, located in

app/views/layouts
(app/views/layouts/store.rhtml in your case).
o Lastly, the file app/views/layouts/application.rhtml.

If found, the saved output of your template will replace the line in the
layout body matching “<%= yield :layout %>”. (Since “:layout” is the
default you could just specify “<%= yield %>”.) The older method, “<%=
@content_for_layout %>” also works.

So, without using partials or explicit renders you would have your
view_details method which would render from the following files:

app/views/store/view_details.rhtml (template for
store_controller#view_details)
app/views/layouts/store.rhtml (layout file for
store_controller.rb)

If you wanted a global layout for all controllers then that layout file
could be:

app/views/layouts/application.rb

Now, both your template AND the selected layout can both still use
partials. For example, I often have common code for the section
in my layout:

app/views/layouts/store.rhtml:

<%= render :partial => 'layouts/head' %> ...

This would render app/views/layouts/_head.rhtml and place that output in
the section of my page.

Hope this helps,

David S.