每当我尝试发布数据时,Rails会回滚两次

时间:2017-08-18 20:12:43

标签: ruby-on-rails database post

所以我正在尝试创建一个应用程序,允许用户创建项目列表并仅查看他们自己创建的列表。每次我按表格上的提交都会发生这种情况

Started POST "/lists" for 127.0.0.1 at 2017-08-18 15:56:40 -0400
Processing by ListsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"VnsMdQq3mw5XabkYCZFTgvgwFc3H89paHA0VE5gunFbiMfa0xGr0p1GEZDHc3yemwBx07K1h4CXuS0l5XL1VbA==", "list"=>{"income"=>"12", "put_into_savings"=>"12", "month"=>"12", "year"=>"21"}, "commit"=>"Create List"}
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
   (0.0ms)  begin transaction
   (0.0ms)  rollback transaction
  Rendering lists/new.html.erb within layouts/application
  Rendered lists/new.html.erb within layouts/application (9.3ms)
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 5], ["LIMIT", 1]]
Completed 200 OK in 269ms (Views: 222.2ms | ActiveRecord: 2.7ms)

这是我的所有代码:

lists_controller.rb
class ListsController < ApplicationController
  def show
    @user = User.find(params[:id])
    @lists = @user.lists
  end

  def new
  end

  def edit
  end

  def create
    @list = List.create(list_params)

    if @list.save
      redirect_to home_url
    else
      render :new
  end
end

  private

  def list_params
    params.require(:list).permit(:income, :put_into_savings, :month, :year)
  end
end

列表/ new.html.erb

 <%= form_for List.new do |f| %>

    <div class="field">
      <%= f.label :income %><br />
      <%= f.text_field :income %>
    </div>
    <div class="field">
      <%= f.label :put_into_savings %><br />
      <%= f.text_area :put_into_savings %>
    </div>
    <div class="field">
      <%= f.label :month %><br />
      <%= f.number_field :month %>
    </div>
    <div class="field">
      <%= f.label :year %><br />
      <%= f.number_field :year %>
    </div>
    <div class="actions">
      <%= f.submit %>
    </div>
  <% end %>

schema.rb

ActiveRecord::Schema.define(version: 20170818185700) do

  create_table "items", force: :cascade do |t|
    t.string "item_name"
    t.integer "item_cost"
    t.string "item_waste"
    t.string "item_group"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "lists", force: :cascade do |t|
    t.integer "income"
    t.integer "put_into_savings"
    t.string "month"
    t.string "year"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "Item_id"
    t.integer "User_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email"
    t.string "password_digest"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "name"
  end

end

的routes.rb

Rails.application.routes.draw do

root 'home#index'
get 'home' => 'home#index'

resources :lists
resources :sessions, only: [:new, :create, :destroy]
resources :users, only: [:new, :create]
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

编辑:这是我的列表模型,抱歉早先忘记了

class List < ApplicationRecord
  has_many :items
  belongs_to :user
end

我对红宝石很新,所以我希望这不是太容易解决的问题,感谢先进的所有帮助,我真的很感激

2 个答案:

答案 0 :(得分:1)

您的模型关联存在逻辑问题。

假设List可以有多个Item,您不应该使用属性item_id声明表List。 (这样做意味着列表只能有一个项目)。我建议你阅读ruby-on-rais-guide-for-associations

对于user_id的问题,您需要在列表对象中显式声明user_id(考虑到您希望在创建List时将List与User关联)。一种方法可以是:

def create
    @list = List.new(list_params)
    @list[:user_id] = current_user.id # Considering you add this method
    if @list.save
      redirect_to home_url
    else
      render :new
  end

在模型中添加一些验证:

class List < ApplicationRecord
  has_many :items
  belongs_to :user

  validates :user_id, presence: true
end

您似乎还需要阅读有关验证的更多信息ruby-on-rais-guide-for-validation。关于你的两次回滚,目前还不清楚原因,但修复你的关联和验证问题,我认为你可以解决它。

尝试阅读有关rails的更多信息,您遇到的问题非常基本。祝你好运!

<强>更新

根据at0misk的回答,解决了两次回滚的问题:

在列表控制器中:

@list = List.new(list_params)
# instead of @list = List.create(list_params)

create方法创建一个新对象并立即保存。因此,rails试图保存两次,首先在方法创建中,然后在方法中保存顺序。

答案 1 :(得分:0)

在您的create方法中,您调用create然后调用save。 Create创建一个对象并将其保存到数据库中,因此调用save是redundent。

您是否检查过您的记录是否正在保存?如果是的话那肯定是错的。我更喜欢使用这种模式,使用new而不是create,然后尝试保存在if块中:

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

void main() {
  runApp(new MaterialApp(home: new HomePage()));
}

class HomePage extends StatefulWidget {
  @override
  HomePageState createState() => new HomePageState();
}

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;
  bool upDown = true;

  @override
  void initState() {
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 180),
    );

    _animation = new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.0, 1.0, curve: Curves.linear),
    );
  }

  @override
  Widget build(BuildContext context) {
    final ui.Size logicalSize = MediaQuery.of(context).size;
    final double _width = logicalSize.width;
    final double _height = logicalSize.height;

    void _up(){
      setState((){
        if(upDown) {
          upDown = false;
          _controller.forward(from: 0.0);
        } else {
          upDown = true;
          _controller.reverse(from: 1.0);
        }
      });
    }

    return new Scaffold(
        body: new Stack(
            children: <Widget>[
              new Positioned(
                  bottom: 0.0,
                  child: new GestureDetector(
                    onTap: _up,
                    child: new AnimatedBuilder(
                      animation: _animation,
                      builder: (BuildContext context, Widget child) {
                      return new Container(
                        height: _height,
                        child: new CustomPaint(
                          painter: new Sky(_width, _height * _animation.value),
                          child: new Container(
                            height: _isRotated ? 0.0 : _height * _animation.value,
                            width: _isRotated ? 0.0 : _width,
                          ),
                        ),
                      );
                    },
                  ),
                )
              ),
              new Positioned(
                bottom: 16.0,
                right: 16.0,
                child: new FloatingActionButton(
                  backgroundColor: new Color(0xFFE57373),
                  child: new Icon(Icons.add),
                  onPressed: (){
                    _up();
                  },
                )
              )
            ]
        )
    );
  }
}

class Sky extends CustomPainter {
  final double _width;
  double _rectHeight;

  Sky(this._width, this._rectHeight);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(
      new Rect.fromLTRB(
          0.0, size.height - _rectHeight, this._width, size.height
      ),
      new Paint()..color = new Color.fromRGBO(0, 153, 255, 0.9)
    );
  }

  @override
  bool shouldRepaint(Sky oldDelegate) {
    return _width != oldDelegate._width || _rectHeight != oldDelegate._rectHeight;
  }
}