У меня есть мастер, который позволяет пользователям выбирать сумму ставки (на этапе show
), а затем я хочу, чтобы они указали адрес (на этапе confirmation
). Я не хочу, чтобы в базе данных ничего не сохранялось до тех пор, пока не были добавлены информация о транзакциях и адресах, поэтому имеет смысл поместить эту функцию в мастер. Это сложнее, чем я думал, потому что я не уверен, как получить мастера, которого я собрал, из других источников, чтобы принять вложенные атрибуты для другой модели. Если вы посмотрите на приведенный ниже код мастера, то увидите, что я предпринял некоторую попытку (которая привела к некоторой ошибке uninitialized constant Transaction::Address
), я просто ... не получаю то, что хочу , Мне не нужны точные решения, но я был бы очень признателен за любые указатели.
Мои ассоциации моделей выглядят так:
class User < ApplicationRecord
has_many :addresses
has_many :items
has_many :transactions
end
class Item < ApplicationRecord
belongs_to :user
belongs_to :address, foreign_key: :address_id
has_many :transactions
accepts_nested_attributes_for :address
end
class Transaction < ApplicationRecord
belongs_to :user
belongs_to :item
belongs_to :address
accepts_nested_attributes_for :address
end
class Address < ActiveRecord::Base
belongs_to :user, foreign_key: :user_id
has_many :items
has_many :transactions
end
Волшебник, которым я пользуюсь, выглядит следующим образом:
module Wizard
module Transaction
STEPS = %w(show confirmation).freeze
class Base
include ActiveModel::Model
attr_accessor :transaction
#do i need an attr_accessor :address?
delegate *::Transaction.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :transaction
# delegate *::Address.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :address
#address is a child of transaction, and i need to collect its attributes in the final step. do i set that up here, or in the final step?
def initialize(transaction_attributes)
@transaction = ::Transaction.new(transaction_attributes)
# @address = ::Address.new(address_attributes)
end
end
class Show < Base
validates :sender_id, :recipient_id, :item_id, :sender_agreement, presence: true
validates :amount, presence: true, numericality: { greater_than: 0 }
end
class Confirmation < Show
end
end
end
Мой контроллер выглядит так:
class TransactionWizardsController < ApplicationController
include TransactionWizard
def confirm
current_step = params[:current_step]
@item = Item.friendly.find(params[:item_id])
@transaction_wizard = wizard_transaction_for_step(current_step)
@transaction_wizard.transaction.attributes = address_params
session[:transaction_attributes] = @transaction_wizard.transaction.attributes
if @transaction_wizard.valid?
next_step = wizard_transaction_next_step(current_step)
create and return unless next_step
redirect_to action: next_step
else
redirect_to action: current_step
end
end
def address_params
params.require(:transaction_wizard).permit(addresses: [:name, :street, :street_2, :state, :zip_code])
end
end
Мои маршруты выглядят так:
resources :items, path: 'art' do
resource :transaction_wizard, only: [:new, :create], path: "bid" do
get :confirmation
post :add_to
post :confirm
end
end
И форма в моем confirmation
виде выглядит так:
<%= form_for @transaction_wizard, as: :transaction_wizard, url: confirm_item_transaction_wizard_path(@item) do |f| %>
<%= f.fields_for @address do |address| %>
<%= address.label "Full name" %>
<%= address.text_field :name, placeholder: "Your full name", autofocus: true %>
<%= address.label "Street address" %>
<%= address.text_field :street, placeholder: "Your street address" %>
<%= address.label "Apt" %>
<%= address.text_field :street_2, placeholder: "Your apt or suite number" %>
<%= address.label "State" %>
<%= address.select :state, options_for_select(states_list), {prompt: 'State'}, class: 'ui selection dropdown' %>
<%= address.label "Zip code" %>
<%= address.text_field :zip_code, placeholder: "Your zip code" %>
<% end %>
<%= hidden_field_tag :current_step, 'confirmation' %>
<%= f.submit "Complete offer" %>
<% end %>