W projekcie używam Rails 5.1.4 i cancancan 2.0 i mam takie modele:
class Reservation < ApplicationRecord
has_one :stretch, dependent: :destroy
has_many :reservation_additional_services, dependent: :destroy
has_many :additional_services, through: :reservation_additional_services
belongs_to :user
enum status: [:submitted, :cancelled, :confirmed, :on_going, :altered, :finished]
accepts_nested_attributes_for :stretch
validates :additional_service_ids, presence: true, unless: ->(reservation) { reservation.is_a?(Reservation::Stay) }
def cancel!
self.cancelled!
end
def costs
additional_costs + additional_services.map(&:price).inject(0){|sum, x| sum + x}
end
end
class AdditionalService < ApplicationRecord
has_many :reservation_additional_services
has_many :reservations, through: :reservation_additional_services
end
i następujący kontroler:
class ReservationsController < ApplicationController
load_and_authorize_resource except: [:index, :create]
def index
@reservations = current_user.reservations
end
def new
@reservation.build_stretch
end
def create
@reservation = Reservation.new(reservation_prams)
@reservation.user = current_user
@reservation.build_stretch unless @reservation.stretch.present?
if @reservation.save
redirect_to reservations_url
else
render :new, status: :not_acceptable
end
end
def show
end
def edit
end
def update
puts "**************************"
p update_params
p params
if @reservation.update_attributes(update_params)
redirect_to reservations_url
else
render :edit, status: :not_acceptable
end
end
def destroy
@reservation.cancel!
redirect_to reservations_url
end
private
def reservation_prams
params.require(:reservation).permit(
stretch_attributes: [:start_date, :end_date],
additional_service_ids: []
)
end
def update_params
params.require(:reservation).permit(
additional_service_ids: []
)
end
end
oraz taki formularz do tworzenia rezerwacji i wiązania jej z AdditionalServices:
= simple_form_for(@reservation,
defaults: { label: false }) do |f|
.row
= f.simple_fields_for :stretch do |sf|
= sf.input :start_date, as: :string, label: t('.labels.start_date'), input_html: { class: 'datepicker' }
= sf.input :end_date, as: :string, label: t('.labels.end_date'), input_html: { class: 'datepicker' }
- if @reservation.is_a?(Reservation::Stay)
= f.input :board, as: :select, label: t('.labels.board'),
collection: Reservation::Stay.boards.keys.collect {|key| [t("reservation.board.#{key}"), key]}, include_blank: false
= f.input :additional_service_ids,
as: :select, input_html: { multiple: true }, label: t('.labels.additional_service'),
collection: AdditionalService.all.collect {|as| ["#{as.name} - #{as.price}", as.id] }
= f.input :room_ids,
as: :select,
input_html: { multiple: true },
label: t('.label.rooms'),
collection: Room.all.collect{ |room| ["#{room.number}", room.id]}
- else
= f.input :additional_service_ids,
as: :select, label: t('.labels.additional_service'),
collection: AdditionalService.all.collect {|as| ["#{as.name} - #{as.price}", as.id] }
.row
= f.submit t('.labels.book')
javascript:
Reservations.initForm();
Przy wykonywaniu akcji create w logach serwera dostaję komunikat: Unpermitted parameters: :additional_service_ids
, gdy drukuje params’y i reservation_prams dostaję:
{"utf8"=>"✓", "authenticity_token"=>"eM4Fxg/HNBpjMk/0apmYRRSSy0h41RmuW6wxcgde9yytQkMMdLf1lyLRciBSrybenVKxNYjaa7kRkuMDgGcT0g==", "reservation"=>{"stretch_attributes"=>{"start_date"=>"2017-09-30", "end_date"=>"2017-10-01"}, "additional_service_ids"=>"1"}, "commit"=>"Zarezerwuj", "controller"=>"reservations", "action"=>"create"}
Unpermitted parameter: :additional_service_ids
{"stretch_attributes"=><ActionController::Parameters {"start_date"=>"2017-09-30", "end_date"=>"2017-10-01"} permitted: true>}
Nie rozumiem czemu additional_service_ids jest unpermitted(ten sam problem występuje też przy akcji update, gdy stworzę rezerwacje z konsoli). Co najlepsze mam kolejny model, który dziedziczy z Reservations i wygląda w ten sposób:
class Reservation::Stay < Reservation
has_and_belongs_to_many :rooms,
foreign_key: 'reservation_id',
association_foreign_key: 'room_id',
join_table: :stays_rooms
validates :room_ids, presence: true
enum board: [:without, :half, :full]
def costs
super + rooms.map(&:price).inject(0){ |sum, x| x * (stretch.end_date.to_date - stretch.start_date.to_date).to_i }
end
end
i taki kontroler:
class StaysController < ApplicationController
load_and_authorize_resource :reservation, parent: false, class: Reservation::Stay, except: [:create]
def new
@reservation.build_stretch
render '/reservations/new'
end
def create
@reservation = Reservation::Stay.new(stay_params)
@reservation.user = current_user
@reservation.build_stretch unless @reservation.stretch.present?
if @reservation.save
redirect_to reservations_url
else
render '/reservations/new', status: :not_acceptable
end
end
def update
if @reservation.update_attributes(update_params)
@reservation.altered!
redirect_to reservations_url
else
render '/reservations/edit', status: :not_acceptable
end
end
private
def stay_params
params.require(:reservation_stay).permit(
:board,
stretch_attributes: [:start_date, :end_date],
additional_service_ids: [],
room_ids: []
)
end
def update_params
params.require(:reservation_stay).permit(
:board,
additional_service_ids: []
)
end
end
i tu wszystko jest już super stay jest tworzony i updateowany bez problemów.