如何在控制器中渲染 :new 并且不丢失 url 中的参数?
How to do render :new in controller and do not lose params from url?
我想在控制器的创建方法中执行 render :new
,问题是,它更改了 url,并且在 url 中我需要一个参数在我的 html 中填写表格(例如:localhost3000/episodes/new?serie_id=8,我用 hidden_field_tag 来完成)。
我的控制器:
def new
@episode= Episode.new
end
def create
# params = { episode: { name: valor, serie_id: valor, ... more} }
@episode = Episode.new(episode_permits)
if @episode.save
redirect_to @episode
else
render :new #This render I want to fix
end
end
我的部分 _form.html.erb:
<%= form_for @chapter do |f| %>
<%= f.label :name, 'Name' %>
<%= f.text_field :name%> <!-- I don't want to use required: true -->
<%= f.hidden_field :serie_id, value: params[:serie_id] %>
<% end %>
如果用户按下从新建到创建表单的按钮,如果他在填写表单时出错,@episode 将无法保存并生成 render :new
然后 url 改为 localhost3000/episodes/
render :new
不改url怎么办?
我尝试使用 redirect_to new_episode_path(:serie_id => params[:episode][:serie_id])
而不是 render :new
,但是这样会丢失用户在表单中输入的内容,并且任何验证都不会显示发生了什么,所以这不是一个选项。
关于项目的更多信息,如果它是模棱两可的:我正在制作一个 Netflix 网络来学习 Rails,一个系列(名称)有很多剧集和一个剧集(名称,serie_id)属于一个系列。
我会改变
<%= f.hidden_field :serie_id, value: params[:serie_id] %>
到
<%= f.hidden_field :serie_id, value: (f.object.serie_id.presence || params[:serie_id]) %>
仅在 serie_id
属性尚未在章节上设置时回退到 params[:serie_id]
。
rails 方法是创建一个 nested resource:
# config/routes.rb
resources :series do
resources :episodes, shallow: true
end
运行 rails routes
查看路由输出。这里的关键是它创建了一个 GET /series/:series_id/episodes/new
路由和一个 POST /series/:series_id/episodes
。这使得两个资源之间的链接变得明确 - 而不是隐藏在请求正文中的东西。
一般来说,如果您使用隐藏字段来传递资源 ID 或用户 ID,那您就错了。
class EpisodesController
before_action :set_series
# GET /series/1/episodes/new
def new
@episode = @series.episodes.new
end
# POST /series/1/episodes
def create
@episode = @series.episodes.new(episode_params)
if @episode.save
redirect_to @episode
else
render :new
end
end
# ...
private
def set_series
@series = Series.find(params[:series_id])
end
def episode_params
params.require(:episode).permit(:foo, :bar, :baz)
end
end
为了将 post 的形式变为 /series/:serie_id/episodes
而不是 /series
我们传递一个数组:
<%= form_for([@series, @episode]) %>
<%= f.label :name, 'Name' %>
<%= f.text_field :name%>
<%= f.submit %>
<% end %>
If the user press the button which sumbit the form from new to create,
if he makes a mistake filling the form, the @episode can't been save
and makes the render :new and then the url change to
localhost3000/episodes/
这是一个非常常见的初学者挂断,这是由于不了解 Rails style REST 的工作原理造成的
在 REST 中,您可以通过 posting 到收集路由 (POST /episodes
) 来创建资源。这意味着浏览器 URL 通过 post 表单更改,这正是它应该的样子。
render :new
不会改变 URL。它只是指示 rails 呈现 app/views/episodes/new.html.erb 视图。
您随后看到的是执行非幂等操作的结果。你不应该重定向回去,因为它既不必要又要求你将所有参数放在不太理想的查询字符串中。
PS
您还应注意 correct singular form of series in English 是 系列 而不是 系列 。不确定 rails 是否会正确地变形,但如果不是,您可以通过设置变形来做到这一点。
# config/intializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'series', 'series'
en
然后您应该重命名模型和关联。
为什么这很重要? The principle of least suprise.
我想在控制器的创建方法中执行 render :new
,问题是,它更改了 url,并且在 url 中我需要一个参数在我的 html 中填写表格(例如:localhost3000/episodes/new?serie_id=8,我用 hidden_field_tag 来完成)。
我的控制器:
def new
@episode= Episode.new
end
def create
# params = { episode: { name: valor, serie_id: valor, ... more} }
@episode = Episode.new(episode_permits)
if @episode.save
redirect_to @episode
else
render :new #This render I want to fix
end
end
我的部分 _form.html.erb:
<%= form_for @chapter do |f| %>
<%= f.label :name, 'Name' %>
<%= f.text_field :name%> <!-- I don't want to use required: true -->
<%= f.hidden_field :serie_id, value: params[:serie_id] %>
<% end %>
如果用户按下从新建到创建表单的按钮,如果他在填写表单时出错,@episode 将无法保存并生成 render :new
然后 url 改为 localhost3000/episodes/
render :new
不改url怎么办?
我尝试使用 redirect_to new_episode_path(:serie_id => params[:episode][:serie_id])
而不是 render :new
,但是这样会丢失用户在表单中输入的内容,并且任何验证都不会显示发生了什么,所以这不是一个选项。
关于项目的更多信息,如果它是模棱两可的:我正在制作一个 Netflix 网络来学习 Rails,一个系列(名称)有很多剧集和一个剧集(名称,serie_id)属于一个系列。
我会改变
<%= f.hidden_field :serie_id, value: params[:serie_id] %>
到
<%= f.hidden_field :serie_id, value: (f.object.serie_id.presence || params[:serie_id]) %>
仅在 serie_id
属性尚未在章节上设置时回退到 params[:serie_id]
。
rails 方法是创建一个 nested resource:
# config/routes.rb
resources :series do
resources :episodes, shallow: true
end
运行 rails routes
查看路由输出。这里的关键是它创建了一个 GET /series/:series_id/episodes/new
路由和一个 POST /series/:series_id/episodes
。这使得两个资源之间的链接变得明确 - 而不是隐藏在请求正文中的东西。
一般来说,如果您使用隐藏字段来传递资源 ID 或用户 ID,那您就错了。
class EpisodesController
before_action :set_series
# GET /series/1/episodes/new
def new
@episode = @series.episodes.new
end
# POST /series/1/episodes
def create
@episode = @series.episodes.new(episode_params)
if @episode.save
redirect_to @episode
else
render :new
end
end
# ...
private
def set_series
@series = Series.find(params[:series_id])
end
def episode_params
params.require(:episode).permit(:foo, :bar, :baz)
end
end
为了将 post 的形式变为 /series/:serie_id/episodes
而不是 /series
我们传递一个数组:
<%= form_for([@series, @episode]) %>
<%= f.label :name, 'Name' %>
<%= f.text_field :name%>
<%= f.submit %>
<% end %>
If the user press the button which sumbit the form from new to create, if he makes a mistake filling the form, the @episode can't been save and makes the render :new and then the url change to localhost3000/episodes/
这是一个非常常见的初学者挂断,这是由于不了解 Rails style REST 的工作原理造成的
在 REST 中,您可以通过 posting 到收集路由 (POST /episodes
) 来创建资源。这意味着浏览器 URL 通过 post 表单更改,这正是它应该的样子。
render :new
不会改变 URL。它只是指示 rails 呈现 app/views/episodes/new.html.erb 视图。
您随后看到的是执行非幂等操作的结果。你不应该重定向回去,因为它既不必要又要求你将所有参数放在不太理想的查询字符串中。
PS
您还应注意 correct singular form of series in English 是 系列 而不是 系列 。不确定 rails 是否会正确地变形,但如果不是,您可以通过设置变形来做到这一点。
# config/intializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'series', 'series'
en
然后您应该重命名模型和关联。
为什么这很重要? The principle of least suprise.