导轨"can't write unknown attribute"



我一整天都在努力解决这个问题,但我解决不了。

我得到这个错误:

ActiveModel::MissingAttributeError in Users::RegistrationsController#add_data
can't write unknown attribute `[:drivlicense_nr, :birth_nation]`

user.rb:

class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
has_one :person
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable,
:omniauthable, omniauth_providers: %i[facebook twitter google_oauth2]

#validate :password_complexity
private
def password_complexity
if password.present? && !password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*d)./)
errors.add :password, 'must include at least one lowercase letter, one uppercase letter, and one digit'
end
end
def self.from_omniauth(auth)
# Either create a User record or update it based on the provider (Google) and the UID
where(email: auth.email, uid: auth.uid).first_or_create do |user|
user.token = auth.credentials.token
user.expires = auth.credentials.expires
user.expires_at = auth.credentials.expires_at
user.refresh_token = auth.credentials.refresh_token
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.skip_confirmation!
user.save!
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session['devise.facebook_data'] && session['devise.facebook_data']['extra']['raw_info']
user.email = data['email'] if user.email.blank?
end
if data = session['devise.google_data'] && session['devise.google_data']['extra']['raw_info']
user.email = data['email'] if user.email.blank?
end
end
end
end

person.rb中,我使用自定义primary_key,因为它们对我的应用程序非常重要。

class Person < ApplicationRecord
belongs_to :user, optional: true
has_many :cars
self.primary_key = %i[drivlicense_nr birth_nation]
VALID_FISCAL_CODE_REGEX = /A^[A-Z]{6}[0-9]{2}[A-Z][0-9]{2}[A-Z][0-9]{3}[A-Z]$z/
validates :fiscal_code, presence: true, length: {is: 16}, format: { with: VALID_FISCAL_CODE_REGEX }
end

人员迁移:

class CreatePeople < ActiveRecord::Migration[5.2]
def change
create_table :people, primary_key: %i[drivlicense_nr birth_nation] do |t|
t.integer     :usercode
t.string      :email, null: false, default: ''
t.string      :plate_nr, limit: 8, null: false, default: ''
t.string      :drivlicense_nr, null: false, default: ''
t.string      :fiscal_code, limit: 16
t.string      :name
t.string      :surname
t.string      :phone_number
t.date        :birth_date
t.string      :birth_nation, limit: 2, null: false, default: 'IT'
t.string      :birth_place
t.string      :current_address
t.string      :city
t.string      :sex                       
t.string      :region
t.string      :zipcode, limit: 5
t.string      :state, limit: 2
t.timestamps  null: false
end
add_index :people, %i[drivlicense_nr birth_nation], name: 'index_people', unique: true
add_index :people, :usercode,    name: 'index_people_on_usercode', unique: true
add_index :people, :fiscal_code, unique: true
# add_index :people, :pcode,                                                      unique: true
end
end

人员迁移:

class DeviseCreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.integer     :usercode
t.belongs_to  :person, index: true
t.boolean     :admin, default: false
t.string      :drivlicense_nr, null: false, default: ''
t.string      :birth_nation, limit: 2, null: false, default: 'IT'
t.string      :tpoliceman_id
## Database authenticatable
t.string      :email
t.string      :encrypted_password
## Recoverable
t.string      :reset_password_token
t.datetime    :reset_password_sent_at
## Rememberable
t.datetime    :remember_created_at
## Trackable
t.integer     :sign_in_count, null: false, default: 0
t.datetime    :current_sign_in_at
t.datetime    :last_sign_in_at
t.string      :current_sign_in_ip
t.string      :last_sign_in_ip
## Confirmable
t.string      :confirmation_token
t.datetime    :confirmed_at
t.datetime    :confirmation_sent_at
t.string      :unconfirmed_email # Only if using reconfirmable
#t.datetime  :updated_at
## Omniauthable
t.string      :provider
t.string      :uid
t.string      :refresh_token
t.string      :token
t.boolean     :expires
t.integer     :expires_at
## Lockable
t.integer     :failed_attempts,                      null: false, default: 0 # Only if lock strategy is :failed_attempts
t.string      :unlock_token # Only if unlock strategy is :email or :both
t.datetime    :locked_at
t.timestamps  null: false
end
add_index :users, :usercode,             unique: true
add_index :users, :email,                unique: true
add_index :users, :reset_password_token, unique: true
add_index :users, :confirmation_token,   unique: true
add_index :users, :unlock_token,         unique: true
#add_index :users, %i[drivlicense_nr birth_nation], name: 'index_users_on_person'#, unique: true
# validates :drivlicense_nr, uniqueness: { scope: :birth_nation }
end
end

我想做的是,在我通过谷歌/脸书注册后,用户必须填写另一张表格。现在,我还需要更新用户,使drivlicense和birth_nation(我的主键(具有相同的值。一旦程序do@person.save!Registration_Controller#add_data:

def add_data
@user = User.find_by_email(params[:email])
if request.get?
@person = Person.new()
render 'oauth_add_data'
elsif request.put?
@person = Person.new(person_params)
@user.update(drivlicense_nr: @person['drivlicense_nr'], birth_nation: @person['birth_nation'])
if @person.save!
flash[:success] = "Sign up process successful"
bypass_sign_in(@user)
redirect_to root_url
else
render 'new'
end
end
end

提前感谢您的帮助和耐心!

更新模式.rb:

ActiveRecord::Schema.define(version: 2020_02_29_181024) do
create_table "car_associated_person", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "plate_nr", limit: 8
t.string "drivlicense_nr"
t.string "birth_nation", limit: 2
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "cars", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "plate_nr", limit: 8, default: "", null: false
t.string "chassis_nr", default: "", null: false
t.string "owner_drivlicense_nr", default: "", null: false
t.string "owner_birth_nation", limit: 2
t.date "enrollment_date", default: "2018-01-01", null: false
t.string "enrollment_nr", default: "", null: false
t.string "enrollment_nation", default: "", null: false
t.string "brand", default: "", null: false
t.string "model", default: "", null: false
t.integer "infraction_nr", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["chassis_nr"], name: "index_cars_on_chassis_nr", unique: true
t.index ["owner_birth_nation"], name: "index_cars_on_owner_birth_nation", unique: true
t.index ["owner_drivlicense_nr"], name: "index_cars_on_owner_drivlicense_nr", unique: true
t.index ["plate_nr"], name: "index_cars_on_plate_nr", unique: true
end
create_table "fines", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.bigint "car_id"
t.integer "fine_nr", default: 0
t.string "plate_nr", limit: 8, default: "", null: false
t.datetime "fine_datetime", default: "2018-01-01 00:00:00", null: false
t.string "fine_address", default: "", null: false
t.string "infraction_article", limit: 10, default: "", null: false
t.string "infraction_informcode"
t.string "infraction_motivation", default: "", null: false
t.integer "deduction_points", default: 0
t.float "fine_amount_reduced", default: 0.0
t.float "procedures_amount", default: 0.0
t.float "fine_total_amount", default: 0.0
t.integer "days_nr_payment", limit: 1, default: 5
t.string "paid", default: "0"
t.string "optional_penalty", default: "None"
t.string "tpoliceman_idnr_1"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["car_id"], name: "index_fines_on_car_id"
t.index ["fine_nr"], name: "index_fines_on_fine_nr", unique: true
t.index ["infraction_informcode"], name: "index_fines_on_infraction_informcode", unique: true
t.index ["plate_nr"], name: "index_fines_on_plate_nr", unique: true
end
create_table "people", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.integer "usercode"
t.string "email", default: "", null: false
t.string "plate_nr", limit: 8, default: "", null: false
t.string "drivlicense_nr", default: ""
t.string "fiscal_code", limit: 16
t.string "name"
t.string "surname"
t.string "phone_number"
t.date "birth_date"
t.string "birth_nation", limit: 2, default: "IT"
t.string "birth_place"
t.string "current_address"
t.string "city"
t.string "sex"
t.string "region"
t.string "zipcode", limit: 5
t.string "state", limit: 2
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["fiscal_code"], name: "index_people_on_fiscal_code", unique: true
t.index ["usercode"], name: "index_people_on_usercode", unique: true
end
create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.integer "usercode"
t.integer "person_id"
t.boolean "admin", default: false
t.string "drivlicense_nr", default: "", null: false
t.string "birth_nation", limit: 2, default: "IT", null: false
t.string "tpoliceman_id"
t.string "email"
t.string "encrypted_password"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "provider"
t.string "uid"
t.string "refresh_token"
t.string "token"
t.boolean "expires"
t.integer "expires_at"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["person_id"], name: "index_users_on_person_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
t.index ["usercode"], name: "index_users_on_usercode", unique: true
end
end

Rails使用id字段作为代理键,然后在应用程序和数据库层中强制该字段的唯一性。这样,您就不必担心创建复合主键(就像在学校一样(。

Rails依赖于很多约定而非配置,主键只是其中之一。您可以配置任何您喜欢的主键,但Rails会与您斗争,尤其是如果您想使用复合键。如果你真的需要,有一块宝石可以帮助你做到这一点,但我会远离它,因为它会带来复杂性。

最新更新