Можно ли сгенерировать поле simple_form из ответа JSON? - PullRequest
1 голос
/ 21 октября 2019

Я ищу способ создания полей simple_form для всех опций, принадлежащих типу room_type, чтобы пользователь мог заполнить option_quantity. Room_type сначала запрашивается в форме, и, следовательно, этот ввод необходимо использовать для параметров, принадлежащих этому room_type.

Текущая попытка

В настоящее время я получаюВсе опции, относящиеся к этому типу комнаты с JQuery, но я не знаю, как действовать дальше (или, может быть, есть лучший способ?)

Ответ текущей попытки

Следующий ответ генерируется с использованием моей текущей попытки.

{rooms: Array(3), options: Array(2), extra_guests: Array(1)}
rooms: (3) [{…}, {…}, {…}]
extra_guests: [{…}]
options: Array(2)
0: {id: 109, room_type_id: 185, name: "Amazing option", description: "", rank: null, …}
1: {id: 110, room_type_id: 185, name: "Second option", description: "", rank: null, …}
length: 2__proto__: Array(0)__proto__: Object

Используя этот JSON, возможно ли создать отдельное поле опции для каждой опции с полем, в котором пользователю предлагается заполнить option_quantity?

код

форма

<%= simple_form_for [@hotel, @reservation] do |f|%>

<%= f.simple_fields_for :rooms do |room| %>
<%= room.input :room_type, collection: @room_type_list, input_html:{
        id: "room_type"
      }%>
<% end %>

<h4>Options</h4>
<!-- List all options for room_type by name and display field for option_quantity  -->
<% end %>

<script >
  // dynamic options for change category
  $(document).on("change", "#room_type", function(){
    var room_type = $(this).val();

    $.ajax({
      url: "/hotels/<%= @hotel.id %>/reservations/new",
      method: "GET",
      dataType: "json",
      data: {room_type: room_type},
      error: function (xhr, status, error) {
        console.error('AJAX Error: ' + status + error);
      },
      success: function (response) {

      var options = response["options"];
      console.log(response);
      console.log(options)
      console.log($("room_type-options").html(response));
      // Code to generate list of options
    }
  });
  });
</script>

схема

create_table "reservation_options", force: :cascade do |t|
    t.bigint "option_id"
    t.bigint "reservation_id"
    t.integer "option_quantity"
    []
    t.index ["option_id"], name: "index_reservation_options_on_option_id"
    t.index ["reservation_id"], name: "index_reservation_options_on_reservation_id"
  end

create_table "options", force: :cascade do |t|
    t.bigint "room_type_id"
    t.string "name"
    []
    t.index ["room_type_id"], name: "index_options_on_room_type_id"
  end

контроллер резервирования

class ReservationsController < ApplicationController
  # skip_before_action :authenticate_user!
  def new
    @hotel = Hotel.find(params[:hotel_id])
    @reservation = Reservation.new
    @room_type_list = @hotel.room_types
    @all_options = @hotel.options
    @rooms = []
    @options = []
    @extra_guests = []

    # # Display rooms/options for category
    if params[:room_type].present?
      @rooms = RoomType.find(params[:room_type]).rooms
      @options = RoomType.find(params[:room_type]).options
      @extra_guests = RoomType.find(params[:room_type]).extra_guests
    end
    if request.xhr?
      respond_to do |format|
        format.json {
        render json: {rooms: @rooms, options: @options, extra_guests: @extra_guests}
      }
      end
    end

    authorize @reservation
  end

private

def reservation_params
      params.require(:reservation).permit(:arrival, :departure, :payment, :reservation_contact_id, option_ids:[],
      reservation_contact_attributes: [:id, :first_name,
      :last_name, :first_name, :last_name, :zipcode, :city, :street, :street_number,
      :email, :phone, :date_of_birth, :country, :company, :gender, :vat_number],
        rooms_attributes: [:id,:name, :room_type_id,
          room_types_attributes: [:id, :name]],
      reservation_options_attributes: [:id, :option_id, :option_quantity, :_destroy,
        options_attributes: [:id, :name, :room_type_id, :description,
          room_types_attributes:[:id, :name]]],
      reservation_extra_guests_attributes: [:id, :extra_guest_id, :extra_guest_quantity, :_destroy,
        extra_guests_attributes: [:id, :name, :room_type_id, :age_table_id,
          room_types_attributes:[:id, :name]]])
  end

модели

class Reservation < ApplicationRecord
  belongs_to :hotel
  belongs_to :room

  has_many :reservation_options, inverse_of: :reservation, dependent: :destroy
  accepts_nested_attributes_for :reservation_options
  has_many :options, through: :reservation_options
end

class Room < ApplicationRecord
  belongs_to :room_type
  validates :name, presence: true
  has_many :reservations, dependent: :destroy
  accepts_nested_attributes_for :room_type
end

class RoomType < ApplicationRecord
  belongs_to :hotel
  has_many :rooms, dependent: :destroy
  accepts_nested_attributes_for :rooms, allow_destroy: true
  has_many :options, dependent: :destroy
  accepts_nested_attributes_for :options, allow_destroy: true
end

class Option < ApplicationRecord
  belongs_to :room_type
  has_many :reservation_options, dependent: :destroy
  has_many :option_prices, dependent: :destroy, inverse_of: :option
end

Ответы на выходы

console.log(response); =>

{rooms: Array(3), options: Array(2), extra_guests: Array(1)}
rooms: (3) [{…}, {…}, {…}]
extra_guests: [{…}]
options: Array(2)
0: {id: 109, room_type_id: 185, name: "Amazing option", description: "", rank: null, …}
1: {id: 110, room_type_id: 185, name: "Second option", description: "", rank: null, …}
length: 2__proto__: Array(0)__proto__: Object

console.log(options); =>

0: {id: 109, room_type_id: 185, name: "Amazing option", description: "", rank: null, …}
1: {id: 110, room_type_id: 185, name: "Second option", description: "", rank: null, …}
length: 2
__proto__: Array(0) 

console.log($("#room_type-options").html(response)); =>

jQuery.fn.init {context: document, selector: "#room_type-options"}

1 Ответ

2 голосов
/ 21 октября 2019

Во-первых, я думаю, что мои маршруты будут выглядеть примерно так:

Rails.application.routes.draw do
  resources :hotels do 
    resources :room_types, shallow: true do 
      scope module: :room_types do 
        resources :options, only: [:index]
      end
    end
  end
 end

Что даст вам:

  room_type_options GET    /room_types/:room_type_id/options(.:format)   room_types/options#index
   hotel_room_types GET    /hotels/:hotel_id/room_types(.:format)        room_types#index
                    POST   /hotels/:hotel_id/room_types(.:format)        room_types#create
new_hotel_room_type GET    /hotels/:hotel_id/room_types/new(.:format)    room_types#new
     edit_room_type GET    /room_types/:id/edit(.:format)                room_types#edit
          room_type GET    /room_types/:id(.:format)                     room_types#show
                    PATCH  /room_types/:id(.:format)                     room_types#update
                    PUT    /room_types/:id(.:format)                     room_types#update
                    DELETE /room_types/:id(.:format)                     room_types#destroy
             hotels GET    /hotels(.:format)                             hotels#index
                    POST   /hotels(.:format)                             hotels#create
          new_hotel GET    /hotels/new(.:format)                         hotels#new
         edit_hotel GET    /hotels/:id/edit(.:format)                    hotels#edit
              hotel GET    /hotels/:id(.:format)                         hotels#show
                    PATCH  /hotels/:id(.:format)                         hotels#update
                    PUT    /hotels/:id(.:format)                         hotels#update
                    DELETE /hotels/:id(.:format)                         hotels#destroy

При необходимости и / или желании вы можете ограничитьсгенерированные маршруты с использованием only: или except:. Например, вы можете сделать:

Rails.application.routes.draw do
  resources :hotels, only: [] do 
    resources :room_types, only: [], shallow: true do 
      scope module: :room_types do 
        resources :options, only: [:index]
      end
    end
  end
end

и получить просто:

room_type_options GET    /room_types/:room_type_id/options(.:format)   room_types/options#index

Вы также можете получить то же самое, выполнив:

Rails.application.routes.draw do
  get 'room_types/:room_type_id/options', to: 'room_types/options#index'
end

В зависимости от того, что плаваеттвоя лодка ...

Тогда я бы изменил свой JS на что-то более похожее на:

<%= simple_form_for [@hotel, @reservation] do |f|%>

<%= f.simple_fields_for :rooms do |room| %>
<%= room.input :room_type, collection: @room_type_list, input_html:{
        id: "room_type"
      }%>
<% end %>

<h4>Options</h4>
  <div id="room-type-options">
    <!-- List all options for room_type by name and display field for option_quantity  -->
  </div>
<% end %>

<script >
  // dynamic options for change category
  $(document).on("change", "#room_type", function(){
    var room_type = $(this).val();
    var room_type_id = # do something here...

    $.ajax({
      url: "/room_types/#{room_type_id}/options",
      method: "GET",
      dataType: "json",
      error: function (xhr, status, error) {
        console.error('AJAX Error: ' + status + error);
      },
      success: function (response) {
        console.log(response);
        $("#room-type-options").html(response)
      }
    });
  });
</script>

Несколько вещей, на которые стоит обратить внимание:

  • You 'Вам понадобится RoomTypes::OptionsController с действием index
  • Действие index должно возвращать html-блоб опций типа комнаты
  • Вам не нужно передавать hotel_id, потому чтоследовательно, RoomType belongs_to :hotel и hotel_id могут быть получены (при необходимости) из RoomType (таким образом, бит shallow: true). Подробнее об этом вы можете прочитать в руководстве Rails Routing from Outside In
  • Вам необходимо самостоятельно заполнить бит var room_type_id =. Вы должны быть в состоянии получить это от room.input, но, возможно, придется немного подправить ваш код - я не уверен,
  • Бит $("#room-type-options").html(response) направлен корректно, но, возможно, придется возиться с ним, потому чтоЯ точно забываю, какова структура ответа
  • Этот бит <div id="room-type-options"> может быть или не быть правильным. У меня нет созданного вручную html, я не знаю, как долго. (Я использую haml.)

Вы можете реализовать RoomTypes::OptionsController, создав файл options_controller.rb в папке app/controllers/room_types. Он будет выглядеть как любой другой контроллер:

# app/controllers/room_types/options_controller.rb
class RoomTypes::OptionsController < ApplicationController

  def index
    @room_type = RoomType.find_by(params[:room_type_id])
    ... do some stuff ...
    ... render some html ...
    ... do a happy dance ...
  end

end

Поскольку этот контроллер имеет пространство имен, вы можете иметь его одновременно с обычными OptionsController и RoomTypesController, и их не будетконфликт.

...