简体   繁体   中英

“1 error prohibiting this from being saved: User can't be blank” - Hartl Ruby on Rails Tutorial

I'm following through the Hartl Rails tutorial, and have created 2 models so far: a 'User' model, and a 'Listing' model (which is essentially the 'Microposts' model from the tutorial except customized to be more of a Craigslist-esque type of post/advertisement rather than Twitter-type status update).

I've setup the ' listing.rb ' model with " belongs_to :user ", and also the ' user.rb ' model with " has_many :listings, dependent: destroy ", even giving 'listings' a user_id index and and created_at index .

However, whenever I try to create a new Listing and submit it, I get the following error:

"1 error prohibiting this listing from being saved: User can't be blank".

No other errors appear, which makes me assume the other columns of 'listing' which are required (name, description, price, and an optional image) are okay, but for some reason the User_id isn't being attached to the created Listing?

What reason would there be for this?

Here are my user.rb, listing.rb, and schema.rb if that helps, along with the controllers:

schema.rb :

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

  create_table "categories", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "listings", force: true do |t|
    t.string   "name"
    t.text     "description"
    t.decimal  "price"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.string   "image"
    t.integer  "user_id"
    t.integer  "category_id"
    t.string   "username"
  end

  add_index "listings", ["user_id", "created_at"], name:     "index_listings_on_user_id_and_created_at"
  add_index "listings", ["user_id"], name: "index_listings_on_user_id"
  add_index "listings", ["username"], name: "index_listings_on_username"

  create_table "users", force: true do |t|
    t.string   "email"
    t.datetime "created_at",                        null: false
    t.datetime "updated_at",                        null: false
    t.string   "password_digest"
    t.string   "remember_digest"
    t.boolean  "admin",             default: false
    t.string   "activation_digest"
    t.boolean  "activated",         default: false
    t.datetime "activated_at"
    t.string   "reset_digest"
    t.datetime "reset_sent_at"
    t.string   "username"
    t.string   "first_name"
    t.string   "last_name"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true

end

user.rb :

class User < ActiveRecord::Base
    has_many :listings, dependent: :destroy
    attr_accessor :remember_token, :activation_token, :reset_token
    before_save   :downcase_email
    before_create :create_activation_digest
    validates :first_name,  presence: true, length: { maximum: 25 }
    validates :last_name, presence: true, length: { maximum: 50 }
    validates :username, presence: true, uniqueness: true, length: {maximum: 50 }
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
    validates :email, presence: true, length: { maximum: 255 },
                                        format: { with: VALID_EMAIL_REGEX },
                                        uniqueness: { case_sensitive: false }
    has_secure_password
    validates :password, length: { minimum: 6 }, allow_blank: true


    class << self
        # Returns the hash digest of the given string.
        def digest(string)
            cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                                                                        BCrypt::Engine.cost
            BCrypt::Password.create(string, cost: cost)
        end

        # Returns a random token.
      def new_token
        SecureRandom.urlsafe_base64
      end
    end

    # Remembers a user in the database for use in persistent sessions.
  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

    # Returns true if the given token matches the digest.
  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end

  # Forgets a user.
  def forget
    update_attribute(:remember_digest, nil)
  end

  # Activates an account.
  def activate
    update_attribute(:activated,  true)
    update_attribute(:activated_at, Time.zone.now)
  end

  # Sends activation email.
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

  # Sets the password reset attributes.
  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest, User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  # Sends password reset email.
  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end

  # Returns true if a password reset has expired.
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end


  private

    # Converts email to all lower-case.
    def downcase_email
        self.email = email.downcase
    end

    # Creates and assigns the activation token and digest.
    def create_activation_digest
        self.activation_token  = User.new_token
        self.activation_digest = User.digest(activation_token)
    end
end

listing.rb :

class Listing < ActiveRecord::Base
  belongs_to :user
  default_scope -> { order('created_at DESC') }
  validates :name, presence: true
  validates :description, presence: true
  validates :price, presence: true
  validates :user_id, presence: true
  mount_uploader :image, ImageUploader
end

Here's the ' Listings ' controller:

class ListingsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: :destroy

  def index
    @listings = Listing.all
  end

  def show
  end

  def new
    @listing = Listing.new
  end

  def edit
  end

  def create
  @listing = Listing.new(listing_params)
    if @listing.save
      redirect_to @listing
      flash[:success] = "Listing was successfully created."
    else
      render 'new'
    end
  end

  def update
    if @listing.update(listing_params)
      flash[:success] = "Listing was successfully updated."
      redirect_to @listing
    else
      render 'edit'
    end
  end

  def destroy
    @listing.destroy
    flash[:success] = "Listing deleted."
    redirect_to request.referrer || root_url
  end

  private

    def listing_params
      params.require(:listing).permit(:name, :description, :price, :image)
    end

    def correct_user
      @listing = current_user.listings.find_by(id: params[:id])
      redirect_to root_url if @listing.nil?
    end
end

and 'Users' controller:

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: :destroy

  def show
    @user = User.find(params[:id])
  end

  def index
    @users = User.paginate(page: params[:page])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end


  private

    def user_params
      params.require(:user).permit(:first_name, :last_name, :username, :email, 
                                   :password, :password_confirmation)
    end

    # Before filters

    # Confirms the correct user.
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

    # Confirms an admin user.
    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end
end

I'm not familiar with the tutorial you're following but the user will not be automatically attached to the newly created listing, you need to do that explicitly. In the create action of ListingsController , replace the first line with the following:

@listing = current_user.listings.build(listing_params)

In this case, the Listing gets build (not saved yet) via the listings association and the current_user is automatically set as the user . You could do the same with:

@listing = Listing.new(listing_params)
@listing.user = current_user

but prefer the shorter version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM