Частичные проверки в многошаговых формах (Мастер) - PullRequest
0 голосов
/ 17 января 2020

У меня есть многошаговая форма, которую я создал с помощью мастера. По сути, первым теплом формы является user / sign_up - что, на мой взгляд, еще не шаг. После нажатия кнопки регистрации пользователь переходит к «реальному» первому шагу, который является :address.

    class UserStepsController < ApplicationController
    include Wicked::Wizard
    steps :address


    def show
      @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
      render_wizard
    end


    def update
      @user = current_user || User.from_omniauth(request.env["omniauth.auth"])
      @user.update!(user_params)
      render_wizard @user
    end

    private

    def user_params
        params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :street, :house_number, :city, :zip_code)
    end

    def redirect_to_finish_wizard(options = nil, params = nil)
        redirect_to new_user_profile_path(current_user)
    end

end

Это, по сути, конец формы. Все сохраняется для пользователя. Теперь я застрял с проверками.

class User < ApplicationRecord

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :omniauthable, omniauth_providers: %i[facebook]

    has_one :profile, dependent: :destroy
    after_create :create_profile
    accepts_nested_attributes_for :profile
    validates :first_name, presence: true
    validates :last_name, presence: true
    validates :street, presence: true
    validates :house_number, presence: true
    validates :city, presence: true
    validates :zip_code, presence: true

    def self.from_omniauth(auth)
        where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
            user.email = auth.info.email
            user.password = Devise.friendly_token[0, 20]
            name = auth.info.name
            user.first_name = name.split(" ")[0]
            user.last_name = name.split(" ")[1]

        end
    end
end

Я бы хотел работать с условными валидациями в моей модели и проверять присутствие только на определенном этапе. Это должно быть легко, так как теоретически у меня есть только один шаг - адрес. Все, что я нахожу в inte rnet, слишком сложно. Вопрос в том, должен ли я как-то изменить user / sign_up на первый шаг в форме, а адрес будет вторым шагом? Или это нормально? И если да, могу ли я просто добавить операторы «if» к атрибутам адреса в моих проверках, каким-то образом определяя, каков шаг адреса? Будет ли это работать так?

def on_address_step?
wizard.steps = wizard.steps.first
end

Или как мне это определить? Тогда валидации будут выглядеть так:

validates :first_name, presence: true
    validates :last_name, presence: true
    validates :street, presence: true, if: :on_address_step?
    validates :house_number, presence: true, if: :on_address_step?
    validates :city, presence: true, if: :on_address_step?
    validates :zip_code, presence: true, if: :on_address_step?

Это, конечно, не так просто. На данный момент это тоже не работает. Как мне нужно изменить это? Спасибо. PS: вот и мой пользовательский контроллер:

class UsersController < ApplicationController

  def index
    @users = User.all
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      session[:user_id] = @user.id
      redirect_to user_steps_path
    else
      render :new
    end
  end

  private

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :street, :house_number, :city, :zip_code)
  end

end

1 Ответ

0 голосов
/ 17 января 2020

Если заполнение адреса является совершенно отдельным процессом, я бы просто выделил адрес в его собственную модель и контроллер.

class User < ApplicationRecord
  # ...
  has_one :address
end

class Address < ApplicationRecord
  # ...
  belongs_to :user
  validates :first_name, :last_name, :street, 
            :house_number, :city, :zip_code, presence: true
end

Это позволяет избежать превращения вашей пользовательской модели в еще более божественный объект и устраняет необходимость в условной проверке, которая делает вашу модель гораздо более осведомленной о шагах UX, чем следовало бы.

# routes.rb
resources :addresses, only: [:new, :create]

class UsersController < ApplicationController
  # ...
  def create
    @user = User.new(params[:user])
    if @user.save
      session[:user_id] = @user.id
      redirect_to new_address_path
    else
      render :new
    end
  end
end

class AddressesController < ApplicationController
  # You should have some sort of method that checks if the user
  # is signed in and redirect otherwise
  before_action :authenticate_user!

  # GET /addresses/new
  def new
    # I'm assuming you have some sort of method to fetch the signed in user
    @address = current_user.build_address
  end

  # POST /addresses
  def create
    @address = current_user.build_address(address_params)
    if @address.save
      redirect_to '/somepath'
    else
      render :new
    end
  end

  def address_params
    params.require(:address).permit(
      :first_name, :last_name, :street, 
      :house_number, :city, :zip_code
    )
  end
end

<%= form_with(model: @address) %>
  # ... inputs
<% end %>

Я сомневаюсь, что вам действительно нужна сложность, связанная с использованием Wicked, и это нормально, если вам действительно нужна длинная многошаговая форма, но в этом случае есть гораздо более простой и лучший выбор дизайна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...