Help with RoR partial views

Hi, and thank you for reading this.

First of all let me explain that i am a developer learning Ruby and
RubyOnRails for future projects, so i am basically a noob that is in
need of some help. :slight_smile:

I created a little RoR project (im using netbeans 6.1 as IDE, but that
should make no difference), that is a very simple product management
web app.
I created it using scaffolding, and CRUD works just fine when called
from the views that the scaffold created. I have some other
controller, the "main" controller with a "welcome" view. This
controller is not tied to any model since it only exists has the
welcome page for the site.

My problem is that i wanted to call the "new" view from "welcome" view
using render :partial=>"products/new", but when ever i call it from
there it gives me an error.

I would like that this partial view would work just like any other
view.
How can i do this?

sample code is bellow

products.rb
[code=]class Product < ActiveRecord::Base
  validates_uniqueness_of :name
end
[/code]

products_controller.rb
[code=]class ProductsController < ApplicationController
  # GET /products
  # GET /products.xml
  def index
    @products = Product.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @products }
    end
  end

  # GET /products/1
  # GET /products/1.xml
  def show
    @product = Product.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml { render :xml => @product }
    end
  end

  # GET /products/new
  # GET /products/new.xml
  def new
    @product = Product.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml { render :xml => @product }
    end
  end

  # GET /products/1/edit
  def edit
    @product = Product.find(params[:id])
  end

  # POST /products
  # POST /products.xml
  def create
    @product = Product.new(params[:product])

    respond_to do |format|
      if @product.save
        flash[:notice] = 'Product was successfully created.'
        format.html { redirect_to(@product) }
        format.xml { render :xml => @product, :status
=> :created, :location => @product }
      else
        format.html { render :action => "new" }
        format.xml { render :xml => @product.errors, :status
=> :unprocessable_entity }
      end
    end
  end

  # PUT /products/1
  # PUT /products/1.xml
  def update
    @product = Product.find(params[:id])

    respond_to do |format|
      if @product.update_attributes(params[:product])
        flash[:notice] = 'Product was successfully updated.'
        format.html { redirect_to(@product) }
        format.xml { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml { render :xml => @product.errors, :status
=> :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.xml
  def destroy
    @product = Product.find(params[:id])
    @product.destroy

    respond_to do |format|
      format.html { redirect_to(products_url) }
      format.xml { head :ok }
    end
  end
end
[/code]

new.html.erb
[code=]<h1>New product</h1>

<% form_for(@product) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :price %><br />
    <%= f.text_field :price %>
  </p>
  <p>
    <%= f.label :type %><br />
    <%= f.text_field :type %>
  </p>
  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

<%= link_to 'Back', products_path %>
[/code]

show.html.erb
[code=]<p>
  <b>Name:</b>
  <%=h @product.name %>
</p>

<p>
  <b>Price:</b>
  <%=h @product.price %>
</p>

<p>
  <b>Type:</b>
  <%=h @product.type %>
</p>

<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>
[/code]

index.html.erb
[code=]<h1>Listing products</h1>

<table>
  <tr>
    <th>Name</th>
    <th>Price</th>
    <th>Type</th>
  </tr>

<% for product in @products %>
  <tr>
    <td><%=h product.name %></td>
    <td><%=h product.price %></td>
    <td><%=h product.type %></td>
    <td><%= link_to 'Show', product %></td>
    <td><%= link_to 'Edit', edit_product_path(product) %></td>
    <td><%= link_to 'Destroy', product, :confirm => 'Are you
sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New product', new_product_path %>
[/code]

edit.html.erb
[code=]<h1>Editing product</h1>

<% form_for(@product) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :price %><br />
    <%= f.text_field :price %>
  </p>
  <p>
    <%= f.label :type %><br />
    <%= f.text_field :type %>
  </p>
  <p>
    <%= f.submit "Update" %>
  </p>
<% end %>

<%= link_to 'Show', @product %> |
<%= link_to 'Back', products_path %>
[/code]

the partial view _new.html.erb (its a copy of new.html.erb)
[code=]<h1>New product</h1>

<% form_for(@product) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :price %><br />
    <%= f.text_field :price %>
  </p>
  <p>
    <%= f.label :type %><br />
    <%= f.text_field :type %>
  </p>
  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

<%= link_to 'Back', products_path %>
[/code]

main_controller.rb
[code=]class MainController < ApplicationController
  def welcome
  end
end[/code]
welcome.html.erb
[code=]<h1>Main#welcome</h1>
<p>Find me in app/views/main/welcome.html.erb</p>

<%= render :partial=>"products/new" %>
[/code]

So my question is, shouldn't the partial view that is being called
from the welcome view, work just like it was being called from
products/new view?

I am aware that this is probably not the best of examples, but imagine
that i have a welcome page, and on that same view i would like to
allow users to search and create new products. And show all the error
messages on the welcome page.
How is it done?

Thank you once more for your time!
CrazyMenConnected

Heh--"it gives me an error" covers a lot of ground. :wink:

I'm guessing you get a complaint about there not being a @product variable when you hit that form_for call in the partial? If that's it, changing your main_controller.rb's welcome action like so should be a fix:

  def welcome
    @product = Product.new
  end

If my guess is wrong, write back w/the error message & stack trace.

Cheers,

-Roy

the partial view _new.html.erb (its a copy of new.html.erb)

Although this isn't technically wrong, it also isn't DRY. What you would
actually want to do is decide what part of the new.html.erb page you
want to share in multiple places. Then, if it were me. I would create a
separate folder in the project to contain partials that will be shared
between different views. Maybe something like app/views/shared. In this
case you probably only want to share the actual form. This way any other
details of the page can be formatted independently (such as headings,
layouts, etc.).

And as mentioned previously you'll still need to make sure you load all
the resources the page needs from the appropriate controller action.

So new.html.erb would end up looking something like this:

I and thank you for your replies.

Heh--"it gives me an error" covers a lot of ground. :wink:

Yes your right, and i am sorry for that, my message was a little
ambiguous.

I have changed the main_controller.rb and i've added the instance
variable has you said. It now looks like this

main_controller.rb
[code]
class MainController < ApplicationController
  def welcome
    @product = Product.new
  end
end
[/code]

There is no error now, the partial is rendered. But now i have another
question.
When i press the "Create" button on the form, all of the output is
redirected back to the products view.
I want the error messages to the displayed on the welcome view if a
user tried to enter the same product twice.
Is it possible to do that? How?

Your partial uses a simple form_for(@product) call. By default that will do a POST to the products/create action, which if it's successful, does a redirect to products/show/<<id for the new product>> (see the create method in your products_controller.rb file).

My advice is to just play around w/rails for a bit & get used to its conventions before you try to bend it to your will. :wink:

HTH,

-Roy