Вложенные ресурсы / pundit - параметр отсутствует или значение пустое: - PullRequest
0 голосов
/ 19 марта 2019

У меня были большие проблемы в течение 2 дней, и мне нужна твоя помощь !!У меня есть 2 модели: сад и резервирование (с вложенными ресурсами и использованием pundit).В «шоу» сада я хочу нажать на кнопку, которая «создает» бронирование прямо из уже созданного сада.Но мне не удается выполнить действие create, которое всегда отображает: param отсутствует или значение пусто: booking.Как сделать так, чтобы «бронирование» появлялось в параметрах и можно было звонить, например, @ booking.booker ??У вас есть решение, не удаляя require (: booking)?

Я пробовал как со страницей "new_booking", так и без нее, но безуспешно.

Большое спасибо !!

booking_controller

class BookingsController < ApplicationController
  def index
  end

  def my_bookings
    @bookings = BookingPolicy::Scope.new(current_user, Booking).scope.where(user: current_user)
  end

  def show
    @booking.garden = @garden
  end

  def new
    @garden = Garden.find(params[:garden_id])
    @garden_id = @garden.id
    @booker_id = current_user.id
    @booking = Booking.new
    authorize @booking

  end

  def create
    @booking = Booking.new(booking_params)
    authorize @booking
    @booking.save
    redirect_to root_path
  end



  private

  def booking_params
    params.require(:booking).permit(:garden_id, :booker_id)
  end
end

gardens_controller

class GardensController < ApplicationController
  before_action :set_garden, only: [:show, :destroy, :edit, :update ]
  def new
    @garden = Garden.new
    authorize @garden
  end

  def create
    @garden = Garden.new(garden_params)
    authorize @garden
    @garden.user = current_user

    respond_to do |format|
      if @garden.save
        format.html { redirect_to @garden, notice: 'Garden was successfully created.' }
        format.json { render :show, status: :created, location: @garden }
      else
        format.html { render :new }
        format.json { render json: @garden.errors, status: :unprocessable_entity }
      end
    end
  end

  def index
      @gardens = policy_scope(Garden)
  end

  def my_gardens
    @gardens = GardenPolicy::Scope.new(current_user, Garden).scope.where(user: current_user)

  end

  def show
    authorize @garden
  end

  def destroy
    authorize @garden

    @garden.destroy
    respond_to do |format|
      format.html { redirect_to gardens_url, notice: 'garden was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  def edit
    authorize @garden
  end

 def update
  authorize @garden

  respond_to do |format|
    if @garden.update(garden_params)
      format.html { redirect_to @garden, notice: 'Garden was successfully updated.' }
      format.json { render :show, status: :ok, location: @garden }
    else
      format.html { render :edit }
      format.json { render json: @garden.errors, status: :unprocessable_entity }
    end
  end
end

  private

  def garden_params
    params.require(:garden).permit(:title, :details, :surface, :address, :availabilities)
  end

  def set_garden
    @garden = Garden.find(params[:id])
  end
end

application_controller

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :authenticate_user!
include Pundit

  # Pundit: white-list approach.
  after_action :verify_authorized, except: [:index, :my_gardens], unless: :skip_pundit?
#  after_action :verify_policy_scoped, only: [:index, :my_gardens], unless: :skip_pundit?

  # Uncomment when you *really understand* Pundit!
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
  def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    redirect_to(root_path)
  end

  private

  def skip_pundit?
    devise_controller? || params[:controller] =~ /(^(rails_)?admin)|(^pages$)/
  end
end

pages_controller

class PagesController < ApplicationController
  skip_before_action :authenticate_user!, only: [:home]

  def home
  end
end

application_record.rb

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

booking.rb

class Booking < ApplicationRecord
  belongs_to :gardens
  has_many :users, through: :gardens
end

garden.rb

class Garden < ApplicationRecord
  belongs_to :user
  has_many :bookings
end

user.rb

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :gardens
  has_many :bookings, through: :gardens
end

application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end

  def index?
    false
  end

  def my_gardens?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope
    end
  end
end

booking_policy.rb

class BookingPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.all
    end
  end

  def create?
    true
  end

  def update?
    user_is_the_owner_or_admin?
  end

  def destroy?
    user_is_the_owner_or_admin?
  end

  def index?
    true
  end

  def show
    scope.where(:id => record.id).exists?
  end

  private

  def user_is_the_owner_or_admin?
    user.admin || record.booker == user
  end
end

garden_policy.rb

class GardenPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
        scope.all #>> permet d'afficher tous les restos dans index
    end
  end

  def create?
    true
  end

  def update?
    user_is_the_owner_or_admin?
  end

  def destroy?
    user_is_the_owner_or_admin?
  end

  def index?
    true
  end

  def show
    scope.where(:id => record.id).exists?
  end

  private

  def user_is_the_owner_or_admin?
    user.admin || record.user == user
  end
end

new_booking.html.erb

<h1>My booking</h1>
<%= simple_form_for [@garden, @booking] do |f| %>
<%= f.input :booker_id, disabled:true %>
<%= f.input :garden_id, disabled:true %>
<%= f.button :submit %>
<% end %>

show_garden.html.erb

<h1>My Garden</h1>
<ul>
<li>Title : <%= @garden.title  %></li>
<li>Address : <%= @garden.address %></li>
<li>Details : <%= @garden.details %></li>
<li>Surface : <%= @garden.surface %></li>
<p> Here will appear the availabilities to select</p>
<% if policy(@garden).destroy? %>
  <li><%= link_to "Delete" %> //
<% end %>
<% if policy(@garden).edit? %>
  <%= link_to "Edit" %></li>
<% end %>
<li><%= link_to "home", gardens_path %></li>
<li><%= link_to "My gardens", my_gardens_path %></li>
<li><%= link_to "Book the Garden", new_garden_booking_path(@garden) %></li> 
</ul>

rout.rb

Rails.application.routes.draw do
  devise_for :users
  delete 'gardens/:id', to: "gardens#destroy", as: :delete_garden
  resources :gardens, except: [:delete] do
    resources :bookings, only: [:new, :create, :show]
  end
  get "my_gardens", to: "gardens#my_gardens", as: :my_gardens
  root to: 'pages#home'
end

Ответы [ 2 ]

0 голосов
/ 19 марта 2019

Проблема заключается в том, как вы создаете бронирование. У меня есть пара предложений. Во-первых, вам не нужно form для создания booking, поскольку вы только передаете значения, вы можете вместо этого использовать link_to с методом POST.

Сначала обновите ваши маршруты:

# ...
resources :gardens, except: [:delete] do
   resource :booking, only: :create  # notice resource is singular
end

Изменить книгу сада ссылку на:

<%= link_to "Book the Garden", garden_booking_path(@garden), method: :post %>

Чтобы звонить booking.booker, вам необходимо обновить Booking модель связи:

class Booking < ApplicationRecord
  belongs_to :garden  # notice garden is singular
  belongs_to :booker, class_name: "User"
end

Затем обновите действие BookingsController create:

def create
  @garden  = Garden.find params[:garden_id]
  @booking = @garden.bookings.build(booker: current_user)

  # ... your pundit authorizations

  if @booking.save
    redirect_to @garden
  end
end

Обратите внимание, что после создания бронирования диспетчер перенаправляет в сад. Это позволит вам показать бронирование. Я думаю, что так лучше, но вы можете перенаправить на root_path, если хотите.

0 голосов
/ 19 марта 2019

Но мне не удается выполнить действие create, которое всегда отображает: param отсутствует или значение пусто: booking

Сильные параметры в Rails - это вложенные хэши.:booking необходимо обернуть вокруг параметров для бронирования объектов.Имена параметров определяются в форме, которая отправляет их на сервер.

<h1>My booking</h1>
<%= simple_form_for [@garden, @booking] do |f| %>
<%= f.input 'booking[booker_id]', disabled:true %>
<%= f.input :garden_id, disabled:true %>
<%= f.button :submit %>
<% end %>

В Rails есть много способов сделать это.Возможно, вам лучше сделать это:

Вы можете использовать fields_for помощника:

= form_tag action_path do

  = fields_for :model_a do |a|
    = a.text_field :name

  = fields_for :model_b do |b|
    = b.text_field :name

  = submit_tag 'Submit'
...