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