创建新记录时,未填充Rails 4,外键列

时间:2014-08-05 12:29:16

标签: ruby-on-rails ruby rails-for-zombies

Rails的新手,请原谅我提出一个简单的问题,但我很难过。

Rails 4.1.1和Ruby 2.1.2

我正在根据我从Code School关注的视频创建一个小型Rails应用程序(Zombie Twitter)。

我有四个控制器:应用程序,欢迎,僵尸和推文。

我有三个型号:User,Zombie,Tweet。

用户(来自Devise),has_one :zombie

Zombie,belongs_to :user has_many :tweets

推文,belongs_to :zombie

用户注册时会创建新的僵尸记录。这很有效。

但是,在创建新推文时,不会填充tweets表中的zombie_id字段。我无法弄清楚这是我的问题。

另外:有人可以解释build和build_model方法以及何时使用它们?当我按@zombie.tweets.build的方式调用某些内容时,我得到一个方法丢失错误。是否有必要在Rails 4.1.1中调用这些方法,还是从早期版本的Rails中保留这些方法?

User.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_one :zombie
  accepts_nested_attributes_for :zombie, allow_destroy: true
end

Zombie.rb

class Zombie < ActiveRecord::Base
  belongs_to :user
  has_many :tweets

  validates_uniqueness_of :zombie_name
end

Tweet.rb

class Tweet < ActiveRecord::Base
  belongs_to :zombie

  attr_accessor :zombie_id

  accepts_nested_attributes_for :zombie
end

ApplicationController.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :set_zombie
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << [zombie_attributes: :zombie_name]
  end

  def set_zombie
    if user_signed_in?
      @zombie = Zombie.includes(:tweets).find_by user_id: current_user.id
    end
  end
end

TweetController.rb

class TweetsController < ApplicationController
  before_action :set_tweet, only: [:show, :edit, :update, :destroy]

  # GET /tweets/new
  def new
    @tweet = current_user.zombie.tweets.new
  end

  # POST /tweets
  # POST /tweets.json
  def create
    @tweet = current_user.zombie.tweets.new(tweet_params)

    logger.debug params

    respond_to do |format|
      if @tweet.save
        format.html { redirect_to :root, notice: 'Tweet was successfully created.' }
        format.json { render :show, status: :created, location: @tweet }
      else
        format.html { render :new }
        format.json { render json: @tweet.errors, status: :unprocessable_entity }
      end
    end
  end

  def set_tweet
    @tweet = Tweet.find(params[:id])
  end

  def tweet_params
    params.require(:tweet).permit(:status, :is_public)
  end
end

/tweets/_form.html.rb

<%= form_for([@zombie, @tweet]) do |f| %>
  <% if @tweet.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@tweet.errors.count, "error") %> prohibited this tweet from being saved:</h2>

      <ul>
      <% @tweet.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label 'Public' %>
    <%= f.check_box :is_public, checked: true %>
  </div>
  <div class="field">
    <%= f.label :status %><br>
    <%= f.text_area :status %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

create_zombies_migration

class CreateZombies < ActiveRecord::Migration
  def change
    create_table :zombies do |t|
      t.string :zombie_name

      t.timestamps
    end

    add_reference :zombies, :user, index: true
    add_index :zombies, [:user_id, :id]
    add_index :zombies, :zombie_name, unique: true
  end
end

create_tweets_migration

class CreateTweets < ActiveRecord::Migration
  def change
    create_table :tweets do |t|
      t.text :status, :limit => 140
      t.boolean :is_public, default: true
      t.timestamps
    end

    add_reference :tweets, :zombie, index: true
    add_index :tweets, [:zombie_id, :id], unique: true
  end
end

最后,这是来自development.log的记录,详细说明了创建推文的POST请求。

enter image description here

2 个答案:

答案 0 :(得分:1)

您需要从attr_accessor :zombie_id删除tweet.rb

在create_tweets_migration

中添加t.references :zombie

zombie_id应该是数据库中的列,而不是虚拟属性。

PS。 accepts_nested_attributes_for :zombietweet.rb也没有任何意义。

答案 1 :(得分:0)

尝试交换

current_user.zombie.tweets.new(tweet_params)

在tweets控制器的创建操作中:

current_user.zombie.tweets.build(tweet_params)

我认为应该在保存推文时填充id。