简体   繁体   English

不使用设计保存的属性和 accepts_nested_attributes_for

[英]Attributes not saving with devise and accepts_nested_attributes_for

I have an almost working sign up form with Devise.我有一个几乎可以工作的 Devise 注册表单。 Whilst it seems to work, it's not saving the fields in my Custaddress table other than the user_id .虽然它似乎有效,但它并没有保存我的Custaddress表中的字段,而不是user_id Any help to work out how to have it save the rest of the information would be great.任何关于如何让它保存其余信息的帮助都会很棒。 The following is greatly truncated!!以下内容大大删减!!

User.rb contains: User.rb 包含:

class User < ApplicationRecord
  has_one :custaddress
  accepts_nested_attributes_for :custaddress
end

Custaddress contains:客户地址包含:

class Custaddress < ApplicationRecord
  has_many :orders
  belongs_to :user
end

Registrations controller contains:注册控制器包含:

As you can see, this just builds on the "standard" Devise controller.如您所见,这只是建立在“标准”Devise 控制器上。 There is no create or new here as I assume it's using the standard methods.这里没有 create 或 new ,因为我假设它使用的是标准方法。

class Users::RegistrationsController < Devise::RegistrationsController
  invisible_captcha only: :create

  protected

  def build_resource(hash = {})
    self.resource = resource_class.new_with_session(hash, session)
    resource.build_custaddress
    # Jumpstart: Skip email confirmation on registration.
    #   Require confirmation when user changes their email only
    resource.skip_confirmation!

    # Registering to accept an invitation should display the invitation on sign up
    if params[:invite] && (invite = AccountInvitation.find_by(token: params[:invite]))
      @account_invitation = invite

    # Build and display account fields in registration form if enabled
    elsif Jumpstart.config.register_with_account?
      account = resource.owned_accounts.first
      account ||= resource.owned_accounts.new
      account.account_users.new(user: resource, admin: true)
    end
  end

  def update_resource(resource, params)
    # Jumpstart: Allow user to edit their profile without password
    resource.update_without_password(params)
  end

  def sign_up(resource_name, resource)
    if cookies[:ordernum]
      order = Order.where(ordernum: cookies[:ordernum]).first
      if order
        order.update!(user: resource, custaddress: resource.custaddress)
        cookies.delete "ordernum"
      end
    end

    sign_in(resource_name, resource)

    # If user registered through an invitation, automatically accept it after signing in
    if params[:invite] && (account_invitation = AccountInvitation.find_by(token: params[:invite]))
      account_invitation.accept!(current_user)

      # Clear redirect to account invitation since it's already been accepted
      stored_location_for(:user)
    end
  end
end

My new.html.erb contains:我的 new.html.erb 包含:

<%= form_with(model: resource, as: resource_name, url: registration_path(resource_name, invite: params[:invite])) do |f| %>

 <%= f.fields_for :custaddress do |cust| %>
      <div class="form-group">
        <%= cust.label "Apartment/Unit Number", class: "font-bold" %>
        <%= cust.text_field :apartment, class: "form-control", placeholder: "Unit 2 or Apartment 307" %>
      </div>
And much more!

My application controller has:我的应用程序控制器有:

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

  include SetCurrentRequestDetails
  include SetLocale
  include Jumpstart::Controller
  include Accounts::SubscriptionStatus
  include Users::NavbarNotifications
  include Users::TimeZone
  include Pagy::Backend
  include CurrentHelper
  include Sortable

  before_action :configure_permitted_parameters, if: :devise_controller?
  before_action :masquerade_user!
  before_action :store_user_location!, if: :storable_location?

  protected

  # To add extra fields to Devise registration, add the attribute names to `extra_keys`
  def configure_permitted_parameters
    extra_keys = [:avatar, :first_name, :last_name, :time_zone, :preferred_language]
    signup_keys = extra_keys + [:terms_of_service, :invite, owned_accounts_attributes: [:name], custaddress_attributes: [:address, :apartment, :city, :state, :country, :postcode, :mobile]]
    devise_parameter_sanitizer.permit(:sign_up, keys: signup_keys)
    devise_parameter_sanitizer.permit(:account_update, keys: extra_keys)
    devise_parameter_sanitizer.permit(:accept_invitation, keys: extra_keys)
  end

  def after_sign_in_path_for(resource_or_scope)
    stored_location_for(resource_or_scope) || super
  end

  # Helper method for verifying authentication in a before_action, but redirecting to sign up instead of login
  def authenticate_user_with_sign_up!
    unless user_signed_in?
      store_location_for(:user, request.fullpath)
      redirect_to new_user_registration_path, alert: t("create_an_account_first")
    end
  end

  def require_current_account_admin
    unless current_account_admin?
      redirect_to root_path, alert: t("must_be_an_admin")
    end
  end

  private

  def storable_location?
    request.get? && is_navigational_format? && !devise_controller? && !request.xhr?
  end

  def store_user_location!
    # :user is the scope we are authenticating
    store_location_for(:user, request.fullpath)
  end
end

My logs are showing:我的日志显示:

Processing by Users::RegistrationsController#create as JS
17:08:57 web.1     |   Parameters: {"authenticity_token"=>"uVphxW4gCQntvHFxRb33dl9cqxv9vlL69Wc2zOMoF1M+pUk8c2HnHwgQFIkMbfmxYraVI7rYBVCPgfSD1u7OHg==", "user"=>{"first_name"=>"[FILTERED]", "last_name"=>"[FILTERED]", "email"=>"[FILTERED]", "password"=>"[FILTERED]", "time_zone"=>"Sydney", "custaddress_attributes"=>{"apartment"=>"", "address"=>"XXXXXXXX", "city"=>"XXXXXXX", "state"=>"XXXXX", "postcode"=>"XXXX", "mobile"=>"XXXXXXXX", "country"=>"XXXXXXX"}, "terms_of_service"=>"1"}, "enc-rmjxhdab"=>"", "button"=>""}

So, I know it's getting the information from the form.所以,我知道它是从表单中获取信息。 However I have no idea where it's saving the Custaddress record.但是我不知道它在哪里保存Custaddress记录。 It only seems to be associating the user_id :它似乎只是关联user_id

Custaddress Create (0.2ms)  INSERT INTO "custaddresses" ("user_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["user_id", 3], ["created_at", "2020-09-25 02:20:39.109187"], ["updated_at", "2020-09-25 02:20:39.109187"]]
12:20:39 web.1     |    (33.9ms)  COMMIT

Can anyone please help me work out why the custaddress isn't saving.任何人都可以帮我弄清楚为什么 custaddress 没有保存。 I've spent hours on this and read every article on google (well it certainly feels like it).我已经花了几个小时在这上面阅读了谷歌上的每一篇文章(当然感觉就是这样)。

I've tried to track this down, to no avail.我试图追踪这一点,但无济于事。

Adding an answer for completeness.添加一个完整的答案。

Devise's create action calls the build_resurce method that you are overriding. Devise 的create操作调用您要覆盖的build_resurce方法。 the problem is that you overrid it for the new action but didn't take into account the create action.问题是您为new操作覆盖了它,但没有考虑create操作。

So, you are doing this:所以,你正在这样做:

  def build_resource(hash = {})
    self.resource = resource_class.new_with_session(hash, session)
    resource.build_custaddress

For the new action there's no issue, resource.build_custaddress will instantiate a new custaddress object for you to be able to use the fields_for helper.对于new操作没有问题, resource.build_custaddress将实例化一个新的custaddress对象,以便您能够使用fields_for助手。

The problem is that, for the create action, at that point resource already has a custaddress with the values from the request (set by the previous line), then you do resource.build_custaddress and replace the current custaddress with a new empty one.问题是,对于create操作,此时resource已经有一个带有请求值的custaddress (由前一行设置),然后您执行resource.build_custaddress并将当前custaddress替换为新的空地址。

The solution is to only build a custaddress if it's not nil:解决方案是只构建一个 custaddress 如果它不为零:

  def build_resource(hash = {})
    self.resource = resource_class.new_with_session(hash, session)
    resource.build_custaddress if resource.custaddress.nil?

That way you'll have a new empty custaddress for the new action, but respect the values from the request for the create , edit or update actions.这样,您将有一个新的空 custaddress 用于new操作,但尊重来自createeditupdate操作请求的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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