是否可以从 JSON 响应中生成 simple_form 字段?
Posted
技术标签:
【中文标题】是否可以从 JSON 响应中生成 simple_form 字段?【英文标题】:Is it possible to generate a simple_form field out of a JSON response? 【发布时间】:2020-02-17 17:34:48 【问题描述】:我正在寻找一种方法来创建属于 room_type 的所有选项的 simple_form 字段,以便用户可以填写 option_quantity。首先在表单中询问 room_type,因此该输入需要用于属于该 room_type 的选项。
当前尝试
目前,我正在使用 JQuery 获得属于此 room_type 的所有选项,但我不知道如何从这里开始(或者也许有更好的方法?)
响应当前尝试
以下响应是使用我当前的尝试生成的。
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"
【问题讨论】:
这似乎是XY Problem。从 ajax 调用返回 html 然后将其插入 DOM 似乎更直接。 感谢您的回复,您完全正确。我调整了我的问题,以提供有关我要解决的问题的更多信息,包括。更多关于我当前代码的输入。 【参考方案1】:首先,我想我会让我的路线看起来像:
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>
这里有几点需要注意:
您需要RoomTypes::OptionsController
和 index
操作
index
操作应返回房间类型选项的 html blob
您不需要传递hotel_id
,因为RoomType belongs_to :hotel
和hotel_id
,因此可以从RoomType
(因此shallow: true
位)派生(如果需要)。您可以在Rails Routing from the Outside In 指南中阅读更多相关信息
您需要自己填写var room_type_id =
位。您应该可以从 room.input
获得,但可能需要稍微调整您的代码 - 我不确定
$("#room-type-options").html(response)
位在方向上是正确的,但可能需要调整一下,因为我完全忘记了响应结构是什么
<div id="room-type-options">
位可能正确也可能不正确。我不知道有多久没有手工制作html了。 (我用的是haml。)
您可以通过在app/controllers/room_types
文件夹中创建options_controller.rb
文件来实现RoomTypes::OptionsController
。它看起来像任何其他控制器:
# 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
同时拥有它,不会有任何冲突。
【讨论】:
非常感谢您的详尽回答。var room_type
已经提供了 room_type_id ,到目前为止,我已经实现了您的答案,直到控制器 RoomTypes::OptionsController
。由于已经有一个 RoomTypes 控制器,我想知道如何实现 ``` RoomTypes::OptionsController```,因为我需要另一个控制器来实现其他(现有)功能?此外,我会将$("#room-type-options").html(response)
的当前输出添加到我的问题中。再次感谢您的帮助!以上是关于是否可以从 JSON 响应中生成 simple_form 字段?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在flutlab中生成flutter .ipa文件?
如何从 protobuf (.proto) 文件中生成 (.json/.yaml) 中的 swagger3 (OpenAPI3) 规范?