Embed a Rails form partial into another page

2019-08-08 01:39发布

I'm building a rails 4.2.0 app with a contact us page (this page does have a semi-empty controller). I'm trying to embed a form partial from another controller.

Here is the code (minus the text):

<% if user_signed_in? %>
 <% render 'enquiries/form' %>
<% end %>

When I run this I get the error 'First argument in form cannot contain nil or be empty'.

My enquiries form looks like a basic rails form:

<%= form_for @enquiry do |f| %>
  <% if @enquiry.errors.any? %>
   <div id="error_explanation">
    <h2><%= pluralize(@enquiry.errors.count, "error") %> prohibited this enquiry from being saved:</h2>
    <ul>
    <% @enquiry.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
    </ul>
   </div>
<% end %>

 <div class="field">
   <%= f.label :subject, "Subject:" %><br>
   <%= f.text_field :subject %>
 </div>
 <div class="field">
   <%= f.label :e_description, "Description:" %><br>
   <%= f.text_area :e_description %>
 </div>
 <div class="actions">
   <%= f.submit %>
 </div>

What could be the possible reason for the error? Or is there a better way of embedding a view into another?

Update/Edit:

Here's the routes:

devise_for :users

resources :rooms do
    resources :viewings
end

resources :rmcats
resources :extras
resources :extracats
resources :enquiries

root :to => redirect('/pages/home')

get 'pages/home'
get 'pages/contactus'

And the enquiry controller:

class EnquiriesController < ApplicationController
  before_action :set_enquiry, only: [:show, :edit, :update, :destroy]

 # GET /enquiries
  def index
   @enquiries = Enquiry.all
  end

 # GET /enquiries/1
  def show
  end

 # GET /enquiries/new
  def new
   @enquiry = Enquiry.new
  end

 # GET /enquiries/1/edit
  def edit
  end

 # POST /enquiries
  def create
   @enquiry = Enquiry.new(enquiry_params)

   if @enquiry.save
    redirect_to @enquiry, notice: 'Enquiry was successfully created.'
   else
    render :new
   end
 end

 # PATCH/PUT /enquiries/1
  def update
   if @enquiry.update(enquiry_params)
    redirect_to @enquiry, notice: 'Enquiry was successfully updated.'
   else
    render :edit
  end
end

 # DELETE /enquiries/1
  def destroy
   @enquiry.destroy
   redirect_to enquiries_url, notice: 'Enquiry was successfully destroyed.'
  end

  private
   # Use callbacks to share common setup or constraints between actions.
   def set_enquiry
    @enquiry = Enquiry.find(params[:id])
   end

   # Only allow a trusted parameter "white list" through.
   def enquiry_params
    params.require(:enquiry).permit(:subject, :e_description)
   end
end

This is the pages controller:

class PagesController < ApplicationController
  around_filter :resource_not_found
  # def home
  # end
  private
  # If resource not found redirect to root and flash error.
  # => For pages this will rarely be needed as it should 404.
  def resource_not_found
     yield
  rescue ActiveRecord::RecordNotFound
    redirect_to root_url, :notice => "Page not found."
  end
end

Edit:

Log:

Started GET "/pages/contactus" for ::1 at 2015-03-21 01:05:25 +0000
Processing by EnquiriesController#new as HTML
  [1m[35mUser Load (0.0ms)[0m  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  Rendered enquiries/_form.html.erb (0.0ms)
  Rendered pages/contactus.html.erb within layouts/application  (0.0ms)
Completed 200 OK in 235ms (Views: 234.6ms | ActiveRecord: 0.0ms)

2条回答
混吃等死
2楼-- · 2019-08-08 02:01

the problem is, that your @enquiry variable is not defined in the context you are rendering the partial. its not defined by the controller action that gets called, you should create a instance of Enquiry by calling

@enquiry = Enquiry.new

in your action.

In Addition

to use it somewhere else i would pass the @enquiry instance variable as a locale variable to the partial

<% render 'enquiries/form', :enquiry => @enquiry %>

your form method should then look like this:

<%= form_for enquiry do |f| %>
  ...
<% end %>

of course all the instances vars should be replaced then. just remove the '@'

EDIT: According to your controller setup you posted above the best way would be to use something like

@enquiry ||= Enquiry.new 

in your form partial to make shure a new instance is created if @enquiry is nil.

查看更多
成全新的幸福
3楼-- · 2019-08-08 02:08

It is telling you that @enquiry is nil at the time it is trying to render the form. You need to call the new action to create the @enqiury for the form to represent.

You could change your route to:

get 'pages/contactus' => 'enquiries#new'

Then in your Enquiry controller:

def new
  @enquiry = Enquiry.new
  render 'pages/contactus'
end

EDIT:

Ok, so now we combine what Friends Systems put in his answer:

<% if user_signed_in? %>
  <%= render 'enquiries/form' enquiry: @enquiry %>
<% end %>

And now change any instance of @enquiry in the form to enquiry

This is because you need to pass the variable to the partial.

查看更多
登录 后发表回答