Rails 4 _form partial creates new record but won't edit current record

北战南征 提交于 2019-12-11 20:00:46

问题


I've built a simple app that has businesses, and those businesses have many reviews. I'm using a partial _form to create/update reviews. The create action works fine, but the update action creates a new review instead of updating the review like its supposed to. Here's the relevant code (irrelevant code removed for brevity):

Code from routes.rb:

resources :businesses do
  resources :reviews
end

Code from models/business.rb:

class Business < ActiveRecord::Base
  has_many :reviews, dependent: :destroy
  validates_associated :reviews
end

Code from models/review.rb:

class Review < ActiveRecord::Base
  belongs_to :business
  belongs_to :user
end

Code from controllers/reviews_controller.rb:

class ReviewsController < ApplicationController
  load_and_authorize_resource

  before_filter :load_business

  def new
  end

  def index
  end

  def create
    @review = @business.reviews.create(review_params)
    @review.user_id = current_user.id
    @review.reviewer = current_user.first_name + ' ' + current_user.last_name
    if @review.save
        redirect_to business_path(@business)
        flash[:notice] = 'Review posted!'
    else
        redirect_to business_path(@business)
        flash[:danger] = 'Your review has an error. Please double check!'
    end
  end

  def edit
    @review = @business.reviews.find(params[:id])
  end

  def update
    @review = @business.reviews.find(params[:id])
    if @review.update(params[review_params])
        redirect_to businesses_path(@business)
        flash[:notice] = 'Review updated!'
    else
        render :action => 'edit'
    end
  end

  def destroy
    @review = @business.reviews.find(params[:id])
    @review.destroy
    redirect_to business_path(@business)
    flash[:notice] = "Review deleted."
  end

  private

  def load_business
    @business = Business.find(params[:business_id])
  end

  def review_params
    params.require(:review).permit(:review, :rating)
  end
end

Code for `reviews/_form.html.erb:

<%= simple_form_for([@business, @business.reviews.build]) do |f| %>
  <%= f.error_notification %>
  <p>
    <%= f.input :review %>
  </p>
  <p>
    <%= f.input :rating, collection: 1..10 %>
  </p>
  <p>
    <%= f.submit :class => 'btn btn-primary' %>
  </p>
<% end %>

The reviews are rendered in the business#show view as a partial. Code for `reviews/_review.html.erb:

<% if !review.user_id.nil? %>
  <div class="well">
    <p>
      <strong>Reviewer:</strong>
      <%= review.reviewer %>
    </p>
    <p>
      <strong>Review:</strong>
      <%= review.review %>
    </p>
    <p>
      <strong>Rating:</strong>
      <%= review.rating %>
    </p>
    <span class = "timestamp">
      posted <%= time_ago_in_words(review.created_at) %> ago.
    </span>
    <% if can? :update, review %>
      <span class = "timestamp">
        <%= link_to "Edit", [:edit, review.business, review], class: 'btn btn-small' %>|
        <%= link_to "Delete", [review.business, review], method: :delete,
                   data: { confirm: 'Are you sure?' } %>
      </span>
    <% end %>
  </div>
<% end %>

Code for reviews/edit.html.erb:

<h1>Edit Review</h1>

<%= render 'form', review: @review %>

<button type="button" class="btn btn-default"><%= link_to 'Back', businesses_path %></button>

The weird thing is, when I click on the "Edit" link in _review.html.erb, the URL that's generated appears to be correct, for example I get http://localhost:3000/businesses/10/reviews/82/edit. However, the _form.html.erb is empty where I would expect it to be populated with the current data for review #82. Furthermore, when I click the "Create Review" button, it creates a new review and doesn't edit review #82.

Here's the server logs after I click "Edit" for an existing review:

Started GET "/businesses/3/reviews/81/edit" for 127.0.0.1 at 2014-08-28 19:18:58 -0500
Processing by ReviewsController#edit as HTML
  Parameters: {"business_id"=>"3", "id"=>"81"}
  User Load (0.8ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 8  ORDER BY "users"."id" ASC LIMIT 1
  Review Load (6.9ms)  SELECT  "reviews".* FROM "reviews"  WHERE "reviews"."id" = $1 LIMIT 1  [["id", 81]]
  Business Load (0.5ms)  SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."id" = $1 LIMIT 1  [["id", 3]]
  Review Load (27.4ms)  SELECT  "reviews".* FROM "reviews"  WHERE "reviews"."business_id" = $1 AND "reviews"."id" = $2 LIMIT 1  [["business_id", 3], ["id", 81]]
  Rendered reviews/_form.html.erb (107.0ms)
  Rendered reviews/edit.html.erb within layouts/application (143.4ms)
Completed 200 OK in 967ms (Views: 669.2ms | ActiveRecord: 35.6ms)


Started POST "/businesses/3/reviews" for 127.0.0.1 at 2014-08-28 19:19:23 -0500
Processing by ReviewsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"<redacted>", "review"=>{"review"=>"Edit review #81.", "rating"=>"1"}, "commit"=>"Create Review", "business_id"=>"3"}
  User Load (0.8ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 8  ORDER BY "users"."id" ASC LIMIT 1
  Business Load (0.6ms)  SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."id" = $1 LIMIT 1  [["id", 3]]
    (28.9ms)  BEGIN
  SQL (132.9ms)  INSERT INTO "reviews" ("business_id", "created_at", "rating", "review", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["business_id", 3], ["created_at", "2014-08-29 00:19:23.470750"], ["rating", 1], ["review", "Edit review #81."], ["updated_at", "2014-08-29 00:19:23.470750"]]
    (39.7ms)  COMMIT
    (0.3ms)  BEGIN
  SQL (0.9ms)  UPDATE "reviews" SET "reviewer" = $1, "updated_at" = $2, "user_id" = $3 WHERE "reviews"."id" = 83  [["reviewer", "<redacted>"], ["updated_at", "2014-08-29 00:19:23.692880"], ["user_id", 8]]
    (17.5ms)  COMMIT
Redirected to http://localhost:3000/businesses/3
Completed 302 Found in 553ms (ActiveRecord: 221.6ms)


Started GET "/businesses/3" for 127.0.0.1 at 2014-08-28 19:19:23 -0500
Processing by BusinessesController#show as HTML
  Parameters: {"id"=>"3"}
  User Load (0.7ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 8  ORDER BY "users"."id" ASC LIMIT 1
  Business Load (0.5ms)  SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."id" = $1 LIMIT 1  [["id", 3]]
    (0.5ms)  SELECT AVG("reviews"."rating") AS avg_id FROM "reviews"  WHERE "reviews"."business_id" = $1  [["business_id", 3]]
  Rendered reviews/_form.html.erb (5.7ms)
  Review Load (0.6ms)  SELECT "reviews".* FROM "reviews"  WHERE "reviews"."business_id" = $1  ORDER BY "reviews"."id" DESC  [["business_id", 3]]
  Rendered reviews/_review.html.erb (58.1ms)
  Rendered businesses/show.html.erb within layouts/application (173.5ms)
  Rendered users/_avatar.html.haml (13.1ms)
  Rendered layouts/_navigation.html.haml (30.9ms)
  Rendered layouts/_messages.html.haml (1.5ms)
  Rendered layouts/_footer.html.haml (16.5ms)
  Rendered layouts/_analytics.html.haml (0.6ms)
  Rendered layouts/_javascripts.html.haml (0.5ms)
Completed 200 OK in 421ms (Views: 391.5ms | ActiveRecord: 2.3ms)

It's clear that the second action in the server log is "Started POST..." which isn't correct. While I'm at it, I may as well provide the relevant routes from rake routes:

business_reviews     GET      /businesses/:business_id/reviews(.:format)          reviews#index
                     POST     /businesses/:business_id/reviews(.:format)          reviews#create
new_business_review  GET      /businesses/:business_id/reviews/new(.:format)      reviews#new
edit_business_review GET      /businesses/:business_id/reviews/:id/edit(.:format) reviews#edit
business_review      GET      /businesses/:business_id/reviews/:id(.:format)      reviews#show
                     PATCH    /businesses/:business_id/reviews/:id(.:format)      reviews#update
                     PUT      /businesses/:business_id/reviews/:id(.:format)      reviews#update
                     DELETE   /businesses/:business_id/reviews/:id(.:format)      reviews#destroy

I've already tried implementing every answer I could find on here, but to no avail. The closest one I've found to being almost my exact problem was this one, but it didn't help either: Rails: Use same partial for creating and editing nested items

Many thanks.


回答1:


According to your output in console, you've got a sql insert stmt before update stmt. Your code in the form cause it. @business.reviews.build will create new review object even when edit.

Update your form_for to:

<%= simple_form_for([@business, @review]) do |f| %>

Instead of @business.reviews.build. You should create objects in controller instead of view.

So you may need to new review objects in your new action too.

  def new
     @review = @business.reviews.build
  end

I have some more suggestions for you to simplify your code that could make things easier.

Use review id to find review, instead of through business.
Such as code in edit and update, you could:

  def edit
    @review = Reviews.find(params[:id])
  end

  def update
    @review = Reviews.find(params[:id])
    ...
  end


来源:https://stackoverflow.com/questions/25560323/rails-4-form-partial-creates-new-record-but-wont-edit-current-record

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!