通过Rails访问has_many上的其他值

我在访问has_many通过名为权限的附加参数的值时遇到了麻烦。 这可能很简单。 我的3个型号是

class User < ActiveRecord::Base has_many :players_users has_many :players, through: :players_users end class Player < ActiveRecord::Base has_many :players_users has_many :users, through: :players_users end class PlayersUser < ActiveRecord::Base belongs_to :user belongs_to :player validates :player_id, uniqueness: { scope: :user_id } end 

我的控制器保存记录没有问题。 将权限值添加到正确的连接表。

 def create @players = Player.new(players_params) @user= current_user if @players.save @player = Player.last @user.save && @user.players_users.create(:player_id =>@player.id, :permission =>"owner") redirect_to '/players' else render 'new' end end 

但是我似乎无法正常访问它,我尝试过

 perm = User.find(current_user).players_users.includes(:Permission) if perm == "owner" 

这给出了一个ActiveRecord :: AssociationNotFoundError,在PlayersUser上找不到名为’Permission’的关联; 也许你拼错了吗?

我也试过了

  perm = User.players_users.where(player_id = @player.id && user_id = current_user) perm.permission 

要么

 perm = User.Player.where(player_id = @player.id && user_id = current_user) 

要么

 perm = User.players.where(player_id = @player.id && user_id = current_user) 

这给出了未定义的方法错误。 未定义的方法`播放器’

我知道这在我的设置中很小,但无法弄清楚它是什么。 任何帮助赞赏。

players_usersplayers与User对象相关联,因此您可以获取结果,

 current_user.players_users.pluck(:permission) 

我之前用自己的代码解决了这个问题 。


我会在一秒钟后发布,但首先你需要重构你的控制器,当前效率很低:

 #app/controllers/players_controller.rb class PlayersController < ApplicationController def create @player = current_user.players.new players_params if @player.save current_user.player_users.find(@player.id).update(permission: "owner") redirect_to players_path end end private def player_params params.require(:player).permit(....) end end 

要访问player_userpermission ,您需要使用以下内容:

 @permission = current_user.player_users.find(@player.id).permission 

-

更多DRY方法(如果您每次明确地将permission设置为owner )将引入一个enumPlayer模型中作为默认值:

 #app/models/player.rb class Player < ActiveRecord::Base enum permission: [:owner, :member, :moderator] #-> defaults to :owner end 

这将取消必须在create方法中定义permission (当然,除非您想要更改它):

 #app/controllers/players_controller.rb class PlayersController < ApplicationController def create @player = current_user.players.new players_params redirect_to players_path if @player.save end end 

要理解这一点,您必须记住,由于player_users是一个连接关联,如果您在current_user对象( current_user.players )上创建一个播放器, ActiveRecord将自动填充它。


协会扩展

关于提取permission数据,我构建了一个脚本,将权限附加到player对象(使用proxy_association.target等):

 #current @player = current_user.players.find params[:player_id] @permission = current_user.player_users.find(params[:player_id]).permission #script @player = current_user.players.find params[:player_id] @permission = @player.permission 

它的工作方式类似于SQL Alias column - 因此,虽然您无法操作数据,但它允许您调用@user.players.find(params[:player_id].permission ..除非它在内存中完成所有操作:

 #app/models/user.rb class User < ActiveRecord::Base has_many :player_users has_many :players, through: :player_users, -> { extending PlayerPermission } end #app/models/concerns/player_permission.rb module PlayerPermission #Load def load permissions.each do |permission| proxy_association.target << permission end end #Private private #Permissions def permissions return_array = [] through_collection.each_with_index do |through,i| associate = through.send(reflection_name) associate.assign_attributes({permission: items[i]}) return_array.concat Array.new(1).fill( associate ) end return_array end ####################### # Variables # ####################### #Association def reflection_name proxy_association.source_reflection.name end #Foreign Key def through_source_key proxy_association.reflection.source_reflection.foreign_key end #Primary Key def through_primary_key proxy_association.reflection.through_reflection.active_record_primary_key end #Through Name def through_name proxy_association.reflection.through_reflection.name end #Through def through_collection proxy_association.owner.send through_name end #Captions def items through_collection.map(&:permission) end #Target def target_collection #load_target proxy_association.target end end 

-

另外, 惯例是保持model名称的所有方面都是singularProductUser )。