为何Membership模型无法通过当前实现创建?求技术排查
问题排查:点击Join按钮后Membership模型未创建,仅跳转页面
点击页面中的“Join”按钮后,Membership模型并未创建,仅跳转至membership的index.html.erb,无其他操作。以下是相关代码及终端信息,协助排查错误:
相关代码
Places index.html.erb
<% @places.each do |p| %> <%= p.name %> <%= link_to "Join", memberships_path(place_id: p.id, user_id: current_user.id, 'membership[place_id]': true), data: { turbo_method: "post" }, class:'', style:'' %> <% end %>
Membership Controller
def create @membership = Membership.new(membership_params) if @membership.save flash[:notice] = "" redirect_back fallback_location: places_path else flash[:error] = "Unable to add membership." redirect_back fallback_location: places_path end end def membership_params params.require(:membership).permit(place_id: params[:place_id], user_id: current_user.id ) end
Membership.rb
class Membership < ApplicationRecord belongs_to :user belongs_to :place end
Place.rb
class Place < ApplicationRecord belongs_to :user has_many :memberships has_many :users, through: :memberships end
User.rb
class User < ApplicationRecord has_many :memberships has_many :places, through: :memberships devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
Routes.rb
resources :places resources :users resources :memberships resources :places do resources :memberships end resources :users do resources :memberships end
终端日志
Started POST "/memberships" for 127.0.0.1 at 2023-04-18 17:32:54 -0400 Processing by MembershipsController#create as TURBO_STREAM Parameters: {"membership"=>{"place_id"=>"true"}, "place_id"=>"1", "user_id"=>"1"} Place Load (0.2ms) SELECT "places".* FROM "places" WHERE "places"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] ↳ app/controllers/memberships_controller.rb:13:in `create' User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]] ↳ app/controllers/memberships_controller.rb:15:in `create' TRANSACTION (0.1ms) BEGIN ↳ app/controllers/memberships_controller.rb:16:in `create' Place Load (0.1ms) SELECT "places".* FROM "places" WHERE "places"."id" = $1 LIMIT $2 [["id", 0], ["LIMIT", 1]] ↳ app/controllers/memberships_controller.rb:16:in `create' TRANSACTION (0.1ms) ROLLBACK ↳ app/controllers/memberships_controller.rb:16:in `create' Redirected to http://127.0.0.1:3000/
错误分析与修复方案
从终端日志可以定位到核心问题,逐个修复如下:
1. 参数传递错误
日志显示membership[place_id]的值是"true",而非实际的场所ID——这是因为你在link_to里错误设置了'membership[place_id]': true,应该替换为实际的p.id。同时无需额外传递顶级的place_id和user_id,统一放在membership命名空间下即可。
修正后的link_to:
<%= link_to "Join", memberships_path('membership[place_id]': p.id), data: { turbo_method: "post" }, class:'', style:'' %>
2. Strong Parameters写法错误
当前membership_params不符合Rails规范,permit方法仅需列出允许的参数名,且用户ID不应从参数获取(避免恶意篡改),直接用current_user.id赋值更安全:
def create # 合并current_user.id,无需从参数接收 @membership = Membership.new(membership_params.merge(user_id: current_user.id)) if @membership.save flash[:notice] = "成功加入该场所" redirect_back fallback_location: places_path else # 显示具体错误信息,方便排查 flash[:error] = "无法加入该场所:#{@membership.errors.full_messages.join(', ')}" redirect_back fallback_location: places_path end end def membership_params params.require(:membership).permit(:place_id) end
3. 路由冗余问题
你同时定义了顶级resources :memberships和嵌套路由,会导致路由冲突。建议保留嵌套路由(更符合“用户加入场所”的业务逻辑),精简路由:
resources :places do resources :memberships, only: [:create] # 只保留创建动作 end # 移除其他memberships相关路由
对应的link_to改用嵌套路由辅助方法:
<%= link_to "Join", place_memberships_path(p), data: { turbo_method: "post" }, class:'', style:'' %>
此时控制器可以进一步简化:
def create @place = Place.find(params[:place_id]) @membership = @place.memberships.build(user_id: current_user.id) if @membership.save flash[:notice] = "成功加入该场所" redirect_back fallback_location: places_path else flash[:error] = "无法加入该场所:#{@membership.errors.full_messages.join(', ')}" redirect_back fallback_location: places_path end end def membership_params params.require(:membership).permit() # 无需参数,通过build方式创建 end
4. 补充唯一性验证
为避免用户重复加入同一场所,在Membership模型添加验证:
class Membership < ApplicationRecord belongs_to :user belongs_to :place validates :user_id, uniqueness: { scope: :place_id, message: "您已经加入过该场所了" } end
内容的提问来源于stack exchange,提问作者superbot
相关产品推荐
相关产品推荐

