在 Rails 4 上,我使用的是 Devise 登录。在第一次登录时,用户被定向到 new_profile_path(@user) 或 profile_path(@profile = @user.profile_id)。我在用户注册期间构建配置文件 ActiveRecord。我想将注册期间创建的 profile.id 传递回用户 ActiveRecord before_save。
我能够成功测试“after_create”,构建工作正常。然后“before_save”我可以通过硬编码 profile_id 来让它工作(见下面的工作代码)。但是,一整天后,我无法弄清楚传递 profile_id 的正确方法。我显然不想要一个硬编码的值。这是我的模型代码。
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_one :profile, :dependent => :destroy, autosave: true
accepts_nested_attributes_for :profile
after_create :build_profile
before_save :set_profile_id
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
def set_profile_id
self.profile_id = 30 # Hard-coding tested and works. Profile built with user_id = user.id and user.profile_id = 30
end
end
class Profile < ActiveRecord::Base
belongs_to :user
#validates :username, presence: true, length: {maximum: 255}, uniqueness: { case_sensitive: false }, format: { with: /\A[a-zA-Z0-9]*\z/, message: "deve contar apenas letras e números" }
#validates :firstname, presence: true, length: {maximum: 255}
#validates :lastname, presence: true, length: {maximum: 255}
#validates :gender, presence: true, inclusion: %w(m f)
#validates :birthday, presence: true
has_many :offers, dependent: :delete_all
before_save :set_address
geocoded_by :address # can also be an IP address
def address
address = "#{street_address}, #{city}, #{state}, #{zipcode}"
end
after_validation :geocode # auto-fetch coordinates
reverse_geocoded_by :latitude, :longitude
after_validation :reverse_geocode # auto-fetch address
has_attached_file :logo_image, :styles => { :medium => "250x250>", :small => "175x175>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
# Validate content type
validates_attachment_content_type :logo_image, :content_type => /\Aimage/
# Validate filename
validates_attachment_file_name :logo_image, :matches => [/png\Z/, /jpe?g\Z/, /JPG?\Z/]
validates_attachment_size :logo_image, :less_than => 2.megabytes
#validates_attachment_presence :avatar
# Explicitly do not validate
#do_not_validate_attachment_file_type :avatar
# This may not be necessary anymore. With 'def address' above. Keeping for now as reference
def set_address
self.address = "#{street_address}, #{city}, #{state}, #{zipcode}"
end
end
class RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
build_resource({})
@validatable = devise_mapping.validatable?
if @validatable
@minimum_password_length = resource_class.password_length.min
end
respond_with self.resource
end
# POST /resource
def create
build_resource(sign_up_params)
resource_saved = resource.save
yield resource if block_given?
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
@validatable = devise_mapping.validatable?
if @validatable
@minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :user_id, :profile_id)
end
def account_update_params
params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :user_id, :profile_id)
end
end
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def index
@profiles = Profile.all
@hash = Gmaps4rails.build_markers(@profiles) do |profile, marker|
marker.lat profile.latitude
marker.lng profile.longitude
marker.infowindow profile.address
end
end
def address
@profile = Profile.find(params[:address])
Geocode.search("@profile")
end
def show
@profiles = Profile.all
@offers = Offer.where(user_id: current_user.id)
@hash = Gmaps4rails.build_markers(@profiles) do |profile, marker|
marker.lat profile.latitude
marker.lng profile.longitude
marker.infowindow profile.address
end
end
def new
@user = current_user # added to solve for session re-direct on sign-in
@profile = Profile.new
end
def create
@profile = Profile.new(profile_params)
#@user.profile_id = @profile.id # added to solve for session re-direct on sign-in
if @profile.save
flash[:notice] = "Profile has been created."
redirect_to @profile
else
flash[:alert] = "Profile has not been created."
render "new"
end
end
def edit
@hash = Gmaps4rails.build_markers(@profiles) do |profile, marker|
marker.lat profile.latitude
marker.lng profile.longitude
marker.infowindow profile.address
end
end
def update
if @profile.update(profile_params)
flash[:notice] = "Profile has been updated."
redirect_to @profile
else
flash[:alert] = "Profile has not been updated."
render "edit"
end
end
def destroy
@profile.destroy
flash[:notice] = "Profile has been destroyed."
redirect_to profiles_path
end
private
def profile_params
params.require(:profile).permit(:id, :firstname, :lastname, :company, :website, :street_address, :city, :state, :zipcode, :phone, :logo_image, :address, :latitude, :longitude, :user_id, :user_email_id)
end
def set_profile
@profile = Profile.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The profile you were looking for could not be found."
redirect_to profiles_path
end
end