如何绕过表单并使用 Rails 中的 link_to 将信息直接传递给创建操作
How to bypass the form and pass information straight to the create action with a link_to in Rails
设置
应用有 3 个模型。成员模型、支持模型和参与模型。成员模型跟踪我的网络应用程序的所有用户。支持模型跟踪用户可以支持我们组织的许多不同方式。参与模型通过跟踪 member_id 和 support_id 显示成员活跃的支持区域来连接其他两个模型。
当前功能
在成员的个人资料中,他们可以查看支持选项卡,该选项卡查询他们可以从支持模型中支持的所有不同领域。然后它检查是否有包括他们的 ID 和该支持区域的 ID 的参与,并说明他们当前是否支持。
期望的结果
我想要一个 link,他们可以单击它来创建或删除参与。因此,如果他们目前正在经济上支持,它会声明他们正在支持并提供 link 以停止支持这种方式,点击后将删除参与记录;反之亦然,如果他们不提供经济支持,link 将显示开始支持并且 link 将创建参与记录。 (最终我将集成一个切换功能,允许成员来回切换,但我需要先解决这个问题。)
问题
有没有办法通过 link_to
将参数发送到 'create' 或 'destroy' 操作以实现此功能?目前我正在执行以下操作但出现错误:
<%=
link_to "Start Supporting",
involvements_path(member_id: current_member.id,
support_id: support_area.id),
method: :post
%>
错误
ActionController::ParameterMissing in InvolvementsController#create
param is missing or the value is empty: involvement
当我执行 byebug 时,我得到以下参数输出:
(byebug) params
<ActionController::Parameters {"_method"=>"post",
"member_id"=>"1",
"support_id"=>"2",
"controller"=>"involvements",
"action"=>"create"}
permitted: false>
这么说,params好像不是空的。。。是不是没通过白名单?有什么想法吗?
代码
耙路
involvements GET /involvements(.:format) involvements#index
POST /involvements(.:format) involvements#create
new_involvement GET /involvements/new(.:format) involvements#new
edit_involvement GET /involvements/:id/edit(.:format) involvements#edit
involvement GET /involvements/:id(.:format) involvements#show
PATCH /involvements/:id(.:format) involvements#update
PUT /involvements/:id(.:format) involvements#update
DELETE /involvements/:id(.:format) involvements#destroy
app/models/involvement.rb
class Involvement < ApplicationRecord
belongs_to :member
end
db/schema.rb
create_table "involvements", force: :cascade do |t|
t.bigint "member_id"
t.integer "support_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["member_id"], name: "index_involvements_on_member_id"
end
app/views/profiles/show.html.erb
<% if @user == 'Owner' %>
<% if @show_page == 'account' %>
<%= render 'profile_account' %>
<% elsif @show_page == 'main' %>
<%= render 'profile_main', locals: { profile: @profile,
user: @user } %>
<% elsif @show_page == 'support' %>
<%= render 'profile_support', locals: { profile: @profile,
user: @user,
supports: @supports,
involvement: @involvements
} %>
<% else %>
<script type="text/javascript">
window.location.href="<%=
member_profile_path(current_member.profile.u_name)
%>"
</script>
<% end %>
<% else %>
<%= render 'profile_main', locals: { profile: @profile,
user: @user } %>
<% end %>
app/views/profiles/_profile_support.html.erb
<h1>This is the Support Page</h1>
<table style="width:50%">
<tr>
<th>Support Area</th>
<th>Support Status</th>
<th>Change Status</th>
</tr>
<% @supports.each do |support_area| %>
<tr>
<th>
<%= link_to support_area.title, support_page_path(support_area.title) %>
</th>
<th>
<% @presence_check = Involvement.exists?(member_id: current_member.id,
support_id: support_area.id) %>
<% if @presence_check %>
Supporting
<% else %>
Not Supporting
<% end %>
</th>
<th>
<%= link_to "Start Supporting",
involvements_path(member_id: current_member.id,
support_id: support_area.id),
method: :post %>
</th>
</tr>
<% end %>
</table>
app/controllers/involvements_controller.rb
class InvolvementsController < ApplicationController
before_action :set_involvement, only: [:show, :edit, :update, :destroy]
def index
@involvements = Involvement.all
end
def show
end
def new
@involvement = Involvement.new
end
def edit
end
def create
@involvement = Involvement.new(involvement_params)
# byebug
respond_to do |format|
if @involvement.save
format.html { redirect_to @involvement,
notice: 'Involvement was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @involvement.update(involvement_params)
format.html { redirect_to @involvement,
notice: 'Involvement was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@involvement.destroy
respond_to do |format|
format.html { redirect_to involvements_url,
notice: 'Involvement was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_involvement
@involvement = Involvement.find(params[:id])
end
# Never trust parameters from the scary internet,
# only allow the white list through.
def involvement_params
# byebug
params.require(:involvement).permit(:member_id, :support_id)
end
end
问题在于如何将参数传递给控制器以及如何在控制器中使用它们。您的控制器执行此操作:
def involvement_params
params.require(:involvement).permit(:member_id, :support_id)
end
这需要 :member_id
和 :support_id
嵌套在 involvement
下,但您将它们作为顶级参数传递给 URL。尝试像这样更新您的 link:
<%= link_to "Start Supporting",
involvements_path(
involvement: {
member_id: current_member.id,
support_id: support_area.id
}
),
method: :post
%>
这应该正确嵌套参数。
设置
应用有 3 个模型。成员模型、支持模型和参与模型。成员模型跟踪我的网络应用程序的所有用户。支持模型跟踪用户可以支持我们组织的许多不同方式。参与模型通过跟踪 member_id 和 support_id 显示成员活跃的支持区域来连接其他两个模型。
当前功能
在成员的个人资料中,他们可以查看支持选项卡,该选项卡查询他们可以从支持模型中支持的所有不同领域。然后它检查是否有包括他们的 ID 和该支持区域的 ID 的参与,并说明他们当前是否支持。
期望的结果
我想要一个 link,他们可以单击它来创建或删除参与。因此,如果他们目前正在经济上支持,它会声明他们正在支持并提供 link 以停止支持这种方式,点击后将删除参与记录;反之亦然,如果他们不提供经济支持,link 将显示开始支持并且 link 将创建参与记录。 (最终我将集成一个切换功能,允许成员来回切换,但我需要先解决这个问题。)
问题
有没有办法通过 link_to
将参数发送到 'create' 或 'destroy' 操作以实现此功能?目前我正在执行以下操作但出现错误:
<%=
link_to "Start Supporting",
involvements_path(member_id: current_member.id,
support_id: support_area.id),
method: :post
%>
错误
ActionController::ParameterMissing in InvolvementsController#create
param is missing or the value is empty: involvement
当我执行 byebug 时,我得到以下参数输出:
(byebug) params
<ActionController::Parameters {"_method"=>"post",
"member_id"=>"1",
"support_id"=>"2",
"controller"=>"involvements",
"action"=>"create"}
permitted: false>
这么说,params好像不是空的。。。是不是没通过白名单?有什么想法吗?
代码
耙路
involvements GET /involvements(.:format) involvements#index
POST /involvements(.:format) involvements#create
new_involvement GET /involvements/new(.:format) involvements#new
edit_involvement GET /involvements/:id/edit(.:format) involvements#edit
involvement GET /involvements/:id(.:format) involvements#show
PATCH /involvements/:id(.:format) involvements#update
PUT /involvements/:id(.:format) involvements#update
DELETE /involvements/:id(.:format) involvements#destroy
app/models/involvement.rb
class Involvement < ApplicationRecord
belongs_to :member
end
db/schema.rb
create_table "involvements", force: :cascade do |t|
t.bigint "member_id"
t.integer "support_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["member_id"], name: "index_involvements_on_member_id"
end
app/views/profiles/show.html.erb
<% if @user == 'Owner' %>
<% if @show_page == 'account' %>
<%= render 'profile_account' %>
<% elsif @show_page == 'main' %>
<%= render 'profile_main', locals: { profile: @profile,
user: @user } %>
<% elsif @show_page == 'support' %>
<%= render 'profile_support', locals: { profile: @profile,
user: @user,
supports: @supports,
involvement: @involvements
} %>
<% else %>
<script type="text/javascript">
window.location.href="<%=
member_profile_path(current_member.profile.u_name)
%>"
</script>
<% end %>
<% else %>
<%= render 'profile_main', locals: { profile: @profile,
user: @user } %>
<% end %>
app/views/profiles/_profile_support.html.erb
<h1>This is the Support Page</h1>
<table style="width:50%">
<tr>
<th>Support Area</th>
<th>Support Status</th>
<th>Change Status</th>
</tr>
<% @supports.each do |support_area| %>
<tr>
<th>
<%= link_to support_area.title, support_page_path(support_area.title) %>
</th>
<th>
<% @presence_check = Involvement.exists?(member_id: current_member.id,
support_id: support_area.id) %>
<% if @presence_check %>
Supporting
<% else %>
Not Supporting
<% end %>
</th>
<th>
<%= link_to "Start Supporting",
involvements_path(member_id: current_member.id,
support_id: support_area.id),
method: :post %>
</th>
</tr>
<% end %>
</table>
app/controllers/involvements_controller.rb
class InvolvementsController < ApplicationController
before_action :set_involvement, only: [:show, :edit, :update, :destroy]
def index
@involvements = Involvement.all
end
def show
end
def new
@involvement = Involvement.new
end
def edit
end
def create
@involvement = Involvement.new(involvement_params)
# byebug
respond_to do |format|
if @involvement.save
format.html { redirect_to @involvement,
notice: 'Involvement was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @involvement.update(involvement_params)
format.html { redirect_to @involvement,
notice: 'Involvement was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@involvement.destroy
respond_to do |format|
format.html { redirect_to involvements_url,
notice: 'Involvement was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_involvement
@involvement = Involvement.find(params[:id])
end
# Never trust parameters from the scary internet,
# only allow the white list through.
def involvement_params
# byebug
params.require(:involvement).permit(:member_id, :support_id)
end
end
问题在于如何将参数传递给控制器以及如何在控制器中使用它们。您的控制器执行此操作:
def involvement_params
params.require(:involvement).permit(:member_id, :support_id)
end
这需要 :member_id
和 :support_id
嵌套在 involvement
下,但您将它们作为顶级参数传递给 URL。尝试像这样更新您的 link:
<%= link_to "Start Supporting",
involvements_path(
involvement: {
member_id: current_member.id,
support_id: support_area.id
}
),
method: :post
%>
这应该正确嵌套参数。