【问题标题】:Rails: How to create has_many through relationships via the ids in the model?Rails:如何通过模型中的 id 通过关系创建 has_many?
【发布时间】:2019-05-13 07:15:56
【问题描述】:

我有三个模型:CustomerBranchCustomerBranch

在客户模型中:

has_many :customer_branches, inverse_of: :customer
has_many :branches, through: :customer_branches

在分支模型中:

has_many :customer_branches, inverse_of: :branch, dependent: :restrict_with_exception
has_many :customers, through: :customer_branches

在 CustomerBranch 模型中:

belongs_to :customer, inverse_of: :customer_branches
belongs_to :branch, inverse_of: :customer_branches

这是一个仅限 api 的应用程序,我将获得一个分支 ID 数组。现在我想根据收到的 id 分配/删除客户的分支。

我有一个解决方案来处理这个问题,但我认为这不是最好的方法。这是我目前的解决方案:

attr_accessor :branches_ids
after_save :assign_branches

def assign_branches
  return if self.branches_ids.nil?
  old_branch_ids = self.branch_ids

  remove_branch_ids = old_branch_ids - self.branches_ids

  self.customer_branches.where(id: remove_branch_ids).delete_all if remove_branch_ids.present?

  self.branches << Branch.where(id: self.branches_ids)
end

有没有更好的方法来处理这个问题?提前致谢!!

【问题讨论】:

  • Rails 不是这样工作的...查看保存相关模型:api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/…
  • 我知道嵌套属性,但不愿意使用它们,因为除了 ids 没有其他字段。
  • 在这种情况下...您可以在表单中使用 association 方法中的构建。客户模型应该只处理有关客户的事情,而不涉及分支机构。这就是单一职责的概念。
  • 这是一个只有 api 的应用程序。我会得到一个 id 数组。

标签: ruby-on-rails associations has-many-through


【解决方案1】:

好的,回答这个问题。您可以直接在客户上设置 ID:

customer = Customer.find(1)
customer.branches_ids = [1,2,3]

Rails 将处理所有的添加和删除。

也适用于新客户:

customer = Customer.new
customer.name = "blabla"
customer.branches_ids = [1,2,3]
customer.save

【讨论】:

    【解决方案2】:

    Ubuntu 20.04

    上构建 Rails 应用程序时我也有同样的担忧

    模型和控制器被命名为一个名为Userbase的模块:

    用户模型

    module Userbase
      class User < ApplicationRecord
    
        # Allow a user to have multiple permissions
        has_many :user_permissions, class_name: Userbase::UserPermission, dependent: :nullify
        has_many :permissions, through: :user_permissions
    
        # Allow a user to have multiple roles
        has_many :user_roles, class_name: Userbase::UserRole, dependent: :nullify
        has_many :roles, through: :user_roles
      end
    end
    

    榜样

    module Userbase
      class Role < ApplicationRecord
    
        # Allow a role to have multiple users
        has_many :user_roles, class_name: Userbase::UserRole, dependent: :nullify
        has_many :users, through: :user_roles
    
        # Allow a role to have multiple permissions
        has_many :role_permissions, class_name: Userbase::Role, dependent: :nullify
        has_many :permissions, through: :role_permissions
      end
    end
    

    权限模型

    module Userbase
      class Permission < ApplicationRecord
    
        # Allow a permission to have multiple users
        has_many :user_permissions, class_name: Userbase::UserPermission, dependent: :nullify
        has_many :users, through: :user_permissions
    
        # Allow a permission to have multiple roles
        has_many :role_permissions, class_name: Userbase::Role, dependent: :nullify
        has_many :roles, through: :role_permissions
      end
    end
    

    角色权限模型

    module Userbase
      class RolePermission < ApplicationRecord
        belongs_to :role, class_name: Userbase::Role
        belongs_to :permission, class_name: Userbase::Permission
      end
    end
    

    用户权限模型

    module Userbase
      class UserPermission < ApplicationRecord
        belongs_to :user, class_name: Userbase::User
        belongs_to :permission, class_name: Userbase::Permission
      end
    end
    

    用户角色模型

    module Userbase
      class UserRole < ApplicationRecord
        belongs_to :user, class_name: Userbase::User
        belongs_to :role, class_name: Userbase::Role
      end
    end
    

    我是这样做的

    我在相应控制器的允许参数中添加了role_ids: []permission_ids: []user_ids: []

    角色控制器

    module Userbase
      module Api
        module V1
          class RolesController < ApplicationController
            before_action :set_role, only: %i[show update destroy]
            .
            .
            .
            private
    
            # Use callbacks to share common setup or constraints between actions.
            def set_role
              @role = Userbase::Role.find(params[:id])
            end
    
            # Only allow a trusted parameter "white list" through.
            def role_params
              params.require(:role).permit(:name, :description, user_ids: [], permission_ids: [] )
            end
          end
        end
      end
    end
    

    用户控制器

    module Userbase
      module Api
        module V1
          class UsersController < ApplicationController
            before_action :set_user, only: %i[show update destroy]
            .
            .
            .
            private
    
            # Use callbacks to share common setup or constraints between actions.
            def set_user
              @role = Userbase::User.find(params[:id])
            end
    
            # Only allow a trusted parameter "white list" through.
            def role_params
              params.require(:user).permit(:name, :description, role_ids: [], permission_ids: [] )
            end
          end
        end
      end
    end
    

    权限控制器

    module Userbase
      module Api
        module V1
          class PermissionsController < ApplicationController
            before_action :set_permission, only: %i[show update destroy]
            .
            .
            .
            private
    
            # Use callbacks to share common setup or constraints between actions.
            def set_permission
              @role = Userbase::Permission.find(params[:id])
            end
    
            # Only allow a trusted parameter "white list" through.
            def role_params
              params.require(:permission).permit(:name, :description, role_ids: [], user_ids: [] )
            end
          end
        end
      end
    end
    

    所以我现在可以创建权限,使用:

    {
        "permission": {
            "name": "create_school",
            "description": "This is the permission to create schools"
        }
    }
    

    我们也可以创建角色,使用:

    {
        "role": {
            "name": "Student",
            "description": "This is the role for students",
            "permission_ids": [1,2]
        }
    }
    

    我们也可以创建用户使用:

    {
        "user": {
            "first_name": "Kelvin",
            "middle_name": "Daniel",
            "last_name": "Wale",
            "email": "kelvin-wale@gmail.com",
            "password": "123456",
            "password_confirmation": "123456",
            "username": "kelvin-wale",
            "role_ids": [1],
            "permission_ids": [1,2]
        }
    }
    

    我还想在每次创建用户时创建一个默认角色,所以我在用户模型中添加了以下方法和before_save回调:

    用户模型

    module Userbase
      class User < ApplicationRecord
        before_save :assign_default_role
    
        # Allow a user to have multiple permissions
        has_many :user_permissions, class_name: Userbase::UserPermission, dependent: :nullify
        has_many :permissions, through: :user_permissions
    
        # Allow a user to have multiple roles
        has_many :user_roles, class_name: Userbase::UserRole, dependent: :nullify
        has_many :roles, through: :user_roles
      end
    
      # Assign the student role by default to users
      def assign_default_role
        role = Userbase::Role.find_by(name: 'Student')
        self.role_ids = role.id
      end
    end
    

    注意:应首先创建角色或使用以下方法将角色播种到数据库中:

    Userbase::Role.delete_all
    
    # Default role
    puts 'Creating default role'
    Userbase::Role.create([{ name: 'Student',
                             description: 'This is the role for students',
                             permission_ids: [1, 2] }])
    

    就是这样。

    我希望这会有所帮助

    【讨论】:

      【解决方案3】:

      您可以在控制器中执行此操作:

      def assign_branches
        customer = Customer.find(params[:id]) // however you gonna get custome whom we gonna assign branches
        customer.branches = Branch.where(id: params[:branch_ids]) //however way you want to get ids
      end
      

      collection= 方法通过适当的添加和删除使集合仅包含提供的对象。所做的更改被持久化到数据库中。更多关于关联的信息,您可以通过:https://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-24
        • 1970-01-01
        • 1970-01-01
        • 2017-01-24
        • 2014-12-05
        • 2015-09-21
        相关资源
        最近更新 更多