Ruby 2.2.0和Rails 4.2破坏了嵌套属性

时间:2015-02-25 21:57:25

标签: ruby-on-rails ruby nested-attributes ruby-on-rails-4.2 ruby-2.2

在我尝试删除其中一个或多个时,在处理嵌套属性时,在Ruby 2.2.0和Rails 4.2中运行的应用程序会给我带来问题。以前版本中的相同代码可以正常工作。我已经通过these instructions阅读了,似乎无法找到答案。

我有一个模型location.rb

class Location < ActiveRecord::Base

  belongs_to :user, dependent: :destroy
  has_many :location_images, dependent: :destroy
  accepts_nested_attributes_for :location_images, allow_destroy: true, :reject_if => lambda { |t| t['location_image'].nil? }

end

和location_image.rb

class LocationImage < ActiveRecord::Base

  belongs_to :location, dependent: :destroy
  has_attached_file :location_image, :styles => { :thumb => '160x120#',
                                         :small => '320x240>',
                                         :large => '640x480>' }

  #validates_attachment_presence :image
  validates_attachment_size :location_image, :less_than => 8.megabytes
  validates_attachment_content_type :location_image, :content_type => /\Aimage\/.*\Z/
end

这是我的locations_controller.rb

class LocationsController < ApplicationController
  before_action :set_location, only: [:show, :edit, :update, :destroy]

  # GET /locations
  # GET /locations.json
  def index
    @locations = Location.all
    @hash = Gmaps4rails.build_markers(@locations) do |location, marker|
      marker.lat location.latitude
      marker.lng location.longitude
      end
  end

  # GET /locations/1
  # GET /locations/1.json
  def show
    @hash = Gmaps4rails.build_markers(@location) do |location, marker|
      marker.lat location.latitude
      marker.lng location.longitude
    end
  end

  # GET /locations/new
  def new
    @location = Location.new
    ( 8 - @location.location_images.count).times { @location.location_images.build }
  end

  # GET /locations/1/edit
  def edit
    ( 8 - @location.location_images.count).times { @location.location_images.build }
  end

  # POST /locations
  # POST /locations.json
  def create
    @location = Location.new(location_params)
    @location.user_id = current_user.id

    respond_to do |format|
      if @location.save
        format.html { redirect_to user_path(current_user[:id]), notice: 'Location was successfully created.' }
        format.json { render :show, status: :created, location: @location }
      else
        format.html { render :new }
        format.json { render json: @location.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /locations/1
  # PATCH/PUT /locations/1.json
  def update
    respond_to do |format|
      if @location.update(location_params)
        format.html { redirect_to @location, notice: 'Location was successfully updated.' }
        format.json { render :show, status: :ok, location: @location }
      else
        format.html { render :edit }
        format.json { render json: @location.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /locations/1
  # DELETE /locations/1.json
  def destroy
    @location.destroy
    respond_to do |format|
      format.html { redirect_to locations_url, notice: 'Location was successfully destroyed.' }
      format.json { head :no_content }
    end
  end


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

    # Never trust parameters from the scary internet, only allow the white list through.
    def location_params
      params.require(:location).permit(:name,
                                       :user_id,
                                       :image,
                                       :latitude,
                                       :longitude,
                                       location_images_attributes: [:id, :location_id, :location_image, :_destroy])
    end
end

我的位置_form.html.erb

<%= simple_form_for(@location) do |f| %>
    <%= f.error_notification %>

    <%= f.input :name %>

    <%= f.input :latitude, :as => 'hidden', label: false, input_html: {id: 'lat'} %>

    <%= f.input :longitude, :as => 'hidden', label: false, input_html: {id: 'lng'} %>

    <%= f.fields_for :location_images do |asset| %>
        <% unless asset.object.new_record? %>
            <div>
              <%= link_to( image_tag(asset.object.location_image.url(:thumb)), asset.object.location_image.url(:large), :class => 'thumbnail' ) %>
              <%= asset.check_box :_destroy %>

            </div>
        <% end %>
    <% end %>

    <% if @location.location_images.count <=5 %>
        <%= f.fields_for :location_images do |builder| %>
            <% if builder.object.new_record? %>
                <%= builder.file_field :location_image %>
            <% end %>
        <% end %>

    <% end %>

    <%= f.button :submit %>

<% end %>

每当我尝试删除图像时,服务器都会挂起。我得到一个内部错误500,这是我以前从未见过的。这是服务器的输出:

Started PATCH "/sl/lokacije/7" for 127.0.0.1 at 2015-02-25 22:26:49 +0100
Processing by LocationsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"WS+xrFB7XnDSwG1JpRztrlrCoBxpSXmEpRVj/rgHP78RrHuabKmclUFn/IWpSsp3wcI5pH+wNpxJ33uyGfUMlw==", "location"=>{"name"=>"sfsdfsdfs", "latitude"=>"51.4976", "longitude"=>"-0.2753", "location_images_attributes"=>{"0"=>{"_destroy"=>"1", "id"=>"8"}, "1"=>{"_destroy"=>"0", "id"=>"9"}}}, "button"=>"", "locale"=>"sl", "id"=>"7"}
  Location Load (0.3ms)  SELECT  `locations`.* FROM `locations` WHERE `locations`.`id` = 7 LIMIT 1
   (0.1ms)  BEGIN
  LocationImage Load (0.3ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 7 AND `location_images`.`id` IN (8, 9)
  SQL (0.3ms)  UPDATE `locations` SET `longitude` = -0.2753, `updated_at` = '2015-02-25 21:26:49.406353' WHERE `locations`.`id` = 7
[AWS S3 200 0.597695 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/008/original/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.166274 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/008/thumb/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.14183 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/008/small/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.172432 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/008/large/Screenshot_2015-02-24_19.52.05.png")  

  SQL (0.3ms)  DELETE FROM `location_images` WHERE `location_images`.`id` = 8
  Location Load (0.3ms)  SELECT  `locations`.* FROM `locations` WHERE `locations`.`id` = 7 LIMIT 1
  LocationImage Load (0.2ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 7
[AWS S3 404 0.13343 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/009/original/Screenshot_2015-02-16_08.23.57.png") AWS::S3::Errors::NoSuchKey No Such Key

[AWS S3 404 0.142441 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/009/thumb/Screenshot_2015-02-16_08.23.57.png") AWS::S3::Errors::NoSuchKey No Such Key

[AWS S3 404 0.16999 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/009/small/Screenshot_2015-02-16_08.23.57.png") AWS::S3::Errors::NoSuchKey No Such Key

[AWS S3 404 0.148309 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/009/large/Screenshot_2015-02-16_08.23.57.png") AWS::S3::Errors::NoSuchKey No Such Key

  SQL (0.3ms)  DELETE FROM `location_images` WHERE `location_images`.`id` = 9
  Location Load (0.2ms)  SELECT  `locations`.* FROM `locations` WHERE `locations`.`id` = 7 LIMIT 1
  LocationImage Load (0.2ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 7
  SQL (0.1ms)  DELETE FROM `locations` WHERE `locations`.`id` = 7
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  Location Load (0.3ms)  SELECT `locations`.* FROM `locations` WHERE `locations`.`user_id` = 1
  LocationImage Load (0.2ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 8
[AWS S3 200 0.135676 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/007/original/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.140119 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/007/thumb/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.15105 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/007/small/Screenshot_2015-02-24_19.52.05.png")  

[AWS S3 200 0.144703 0 retries] head_object(:bucket_name=>"inter_d",:key=>"location_images/location_images/000/000/007/large/Screenshot_2015-02-24_19.52.05.png")  

  SQL (0.3ms)  DELETE FROM `location_images` WHERE `location_images`.`id` = 7
  Location Load (0.2ms)  SELECT  `locations`.* FROM `locations` WHERE `locations`.`id` = 8 LIMIT 1
  LocationImage Load (0.2ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 8
  SQL (0.1ms)  DELETE FROM `locations` WHERE `locations`.`id` = 8
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  Location Load (0.2ms)  SELECT `locations`.* FROM `locations` WHERE `locations`.`user_id` = 1
  LocationImage Load (0.2ms)  SELECT `location_images`.* FROM `location_images` WHERE `location_images`.`location_id` = 9
  SQL (0.2ms)  DELETE FROM `locations` WHERE `locations`.`id` = 9
   (0.4ms)  ROLLBACK
Completed 500 Internal Server Error in 2532ms

RuntimeError - Can't modify frozen hash:
  activerecord (4.2.0) lib/active_record/attribute_set/builder.rb:43:in `[]='
  activerecord (4.2.0) lib/active_record/attribute_set.rb:39:in `write_from_user'
  activerecord (4.2.0) lib/active_record/attribute_methods/write.rb:74:in `write_attribute_with_type_cast'
  activerecord (4.2.0) lib/active_record/attribute_methods/write.rb:56:in `write_attribute'
  activerecord (4.2.0) lib/active_record/attribute_methods/dirty.rb:92:in `write_attribute'
  activerecord (4.2.0) lib/active_record/transactions.rb:393:in `restore_transaction_record_state'
  activerecord (4.2.0) lib/active_record/transactions.rb:324:in `rolledback!'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/transaction.rb:73:in `rollback_records'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/transaction.rb:151:in `rollback'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/transaction.rb:183:in `rollback_transaction'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/transaction.rb:190:in `rescue in within_new_transaction'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/transaction.rb:205:in `within_new_transaction'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
  activerecord (4.2.0) lib/active_record/transactions.rb:220:in `transaction'
  activerecord (4.2.0) lib/active_record/transactions.rb:344:in `with_transaction_returning_status'
  activerecord (4.2.0) lib/active_record/persistence.rb:248:in `update'
  app/controllers/locations_controller.rb:55:in `block in update'
  actionpack (4.2.0) lib/action_controller/metal/mime_responds.rb:211:in `respond_to'
  app/controllers/locations_controller.rb:54:in `update'
  actionpack (4.2.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
  actionpack (4.2.0) lib/abstract_controller/base.rb:198:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
  activesupport (4.2.0) lib/active_support/callbacks.rb:117:in `call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
  activesupport (4.2.0) lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:234:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:234:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:308:in `block (2 levels) in halting'
  route_translator (4.0.0) lib/route_translator/extensions/action_controller.rb:20:in `set_locale_from_url'
  activesupport (4.2.0) lib/active_support/callbacks.rb:427:in `block in make_lambda'
  activesupport (4.2.0) lib/active_support/callbacks.rb:307:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:234:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
  activesupport (4.2.0) lib/active_support/callbacks.rb:92:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.0) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.0) lib/active_support/notifications.rb:164:in `instrument'
  actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  actionpack (4.2.0) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.2.0) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.0) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.0) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.2.0) lib/action_controller/metal.rb:195:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.0) lib/action_controller/metal.rb:236:in `block in action'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:73:in `dispatch'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:42:in `serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.0) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:802:in `call'
  rack-pjax (0.8.0) lib/rack/pjax.rb:12:in `call'
  warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.3) lib/warden/manager.rb:34:in `call'
  rack (1.6.0) lib/rack/etag.rb:24:in `call'
  rack (1.6.0) lib/rack/conditionalget.rb:38:in `call'
  rack (1.6.0) lib/rack/head.rb:13:in `call'
  remotipart (1.2.1) lib/remotipart/middleware.rb:27:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/flash.rb:260:in `call'
  rack (1.6.0) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.6.0) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/cookies.rb:560:in `call'
  activerecord (4.2.0) lib/active_record/query_cache.rb:36:in `call'
  activerecord (4.2.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:647:in `call'
  activerecord (4.2.0) lib/active_record/migration.rb:378:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.0) lib/active_support/callbacks.rb:88:in `_run_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:734:in `_run_call_callbacks'
  activesupport (4.2.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  web-console (2.0.0) lib/action_dispatch/debug_exceptions.rb:18:in `middleware_call'
  web-console (2.0.0) lib/action_dispatch/debug_exceptions.rb:13:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.2.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.0) lib/rails/rack/logger.rb:20:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.6.0) lib/rack/methodoverride.rb:22:in `call'
  rack (1.6.0) lib/rack/runtime.rb:18:in `call'
  activesupport (4.2.0) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  actionpack (4.2.0) lib/action_dispatch/middleware/static.rb:113:in `call'
  rack (1.6.0) lib/rack/sendfile.rb:113:in `call'
  railties (4.2.0) lib/rails/engine.rb:518:in `call'
  railties (4.2.0) lib/rails/application.rb:164:in `call'
  rack (1.6.0) lib/rack/lock.rb:17:in `call'
  rack (1.6.0) lib/rack/content_length.rb:15:in `call'
  rack (1.6.0) lib/rack/handler/webrick.rb:89:in `service'
  /Users/luka/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:138:in `service'
  /Users/luka/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:94:in `run'
  /Users/luka/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'



Started POST "/__better_errors/15afdce6b6d2e168/variables" for 127.0.0.1 at 2015-02-26 11:15:37 +0100

问题是,同样的形式在ruby 2.1.2和rails 4.1.5中没有任何故障。

非常感谢任何建议或解决方法。

祝你好运, 卢卡

更新: 即使我通过控制台:

l=Location.last

返回上一个位置

l.location_images.find(11)

返回相应的记录。如果那时我去

l.location_images.find(11).destroy

我遇到与运行服务器时相同的错误。这可能是由于我做错了什么还是错误?

1 个答案:

答案 0 :(得分:0)

问题在于我。我把dependent: :destroy放在两个模型中。删除一个时,它也试图删除父。