【问题标题】:has_many :through 4r post contributionshas_many :通过 4r 帖子贡献
【发布时间】:2016-01-31 05:00:00
【问题描述】:

我在理解如何设置贡献控制器和视图中的表单时遇到了一些麻烦。我在视图中设置了一些表单,所以我知道连接表可以工作。

截至目前,一个帖子属于_to user && a user has_many posts

目标:
1. user1 创建 post - 属于 user1
2. user2 请求加入 user1_post 作为贡献者
3. user1 接受或拒绝请求
4. user2 现在是 user1_post 的贡献者
5. user1 可以移除 user2 作为贡献者

得到has_many:通过正确设置并在控制台中对其进行了测试

contribution.rb

class Contribution < ActiveRecord::Base
  belongs_to :post
  belongs_to :user

  def accept
    self.accepted = true
  end
end

post.rb

class Post < ActiveRecord::Base
  belongs_to :author, class_name: 'User'
  has_many :contribution_requests, -> { where(accepted: false) }, class_name: 'Contribution'
  has_many :contributions, -> { where(accepted: true) }
  has_many :contributors, through: :contributions, source: :user
end

user.rb

class User < ActiveRecord::Base
  has_many :posts, foreign_key: 'author_id'
  has_many :contribution_requests, -> { where(accepted: false) }, class_name: 'Contribution'
  has_many :contributions, -> { where(accepted: true) }
  has_many :contributed_posts, through: :contributions, source: :post
end

contributions_controller.rb

class ContributionsController < ApplicationController
  def create
    @contribution = current_user.contributions.build(:user_id => params[:id])
    if @contribution.save
        flash[:notice] = "Added contributor."
        redirect_to posts_path(@post)
    else
        flash[:error] = "Unable to add contributor."
        redirect_to posts_path(@post)
    end
  end

  def destroy
    @contribution = current_user.contributions.find(params[:id])
    @contribution.destroy
        flash[:notice] = "Removed contributor."
        redirect_to root_url
    end
end

【问题讨论】:

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


    【解决方案1】:

    没有太多上下文,这就是我要做的:

    #config/routes.rb
    resources :posts do
       resources :contributions, only: [:create, :destroy] #-> can use posts#edit to add extra contributions
    end
    
    #app/controllers/posts_controller.rb
    class PostsController < ApplicationController
       def edit
          @post = Post.find params[:id]
       end
    end
    
    #app/views/contributions/edit.html.erb
    <%= form_for @post do |f| %>
        # @post form 
    <% end %>
    ## contributor add / remove form (select boxes) 
    
    #app/controllers/contributions_controller.rb
    class ContributionsController < ApplicationController
       def create
          @post = Post.find params[:post_id]
          @contribution = current_user.contributions.new contribution_params
          @contribution.post = @post
    
          notice = @contribution.save ? "Added Contributor" : "Unable to add contributor"
          redirect_to @post, notice: notice
       end
    
       def destroy
          @contribution = current_user.contributions.find params[:id]
          @contribution.destroy
    
          redirect_to root_url, notice: "Removed Contributor"
    end
    
       private
    
       def contribution_params 
          params.require(:contribution).permit(:user, :post, :accepted)
       end
    end
    

    顺便说一句,您应该查看ActiveRecordExtension 为您的conbtributions 关联(而不是多个关联)提供一些方法:

    #app/models/post.rb
    class Post < ActiveRecord::Base
       has_many :contributions, -> { extending ContributionExtension }
    end
    
    #app/models/user.rb
    class User < ActiveRecord::Base
       has_many :contributions, -> { extending ContributionExtension }
    end
    
    #app/models/concerns/contribution_extension.rb
    class ContributionExtension
       def requests(status=false)
         where accepted: status
       end
    
       def accepted(status=true)
         where accepted: status
       end
    end
    
    @post.contirbutions.requets
    @post.contributions.accepted
    
    @user.contributions.requests
    @user.contributions.accepted
    

    --

    此外,您应该考虑为您的 Contribution 模型实现 state_machine

    #app/models/contribution.rb
    class Contribution < ActiveRecord::Base
       state_machine :accepted, initial: :pending do
          event :accept do
             transition [:pending, :denied] => :accepted
          end
    
          event :deny do
             transition [:pending, :accepted] => :denied
          end
       end
    end
    

    太棒了article about it here

    这将允许您调用:

    @contribution = current_user.contributions.find params[:id]
    @contribution.accept
    

    它还会为您提供其他几种很酷的方法:

    @contribution.accepted?
    @contribution.state
    

    【讨论】:

    • 从未真正使用过状态机 - 我试图了解如何在 post-show.html 中设置发布请求按钮 - 以及如何建立待处理状态 - 我正在猜测是否声明?
    • 发布请求按钮?你能提供更多的背景信息吗?
    • 好的,可以说 manuel user1 创建了一个现在属于我的帖子 - rich = user2 必须访问我的帖子并单击 请求按钮 才能以贡献者 - 用户 1 发送和接收请求后,他可以查看帖子中的请求列表并接受或拒绝请求
    • 状态机只是为你的对象添加了一堆实例方法。这样,您无需声明 self.accept - 您将能够从状态机本身使用 @post = Post.find x @post.accept
    • 所以在视图中创建请求: : 我现在可能不得不推迟这个设置 - 我很困惑.. 谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 2011-09-13
    • 2016-03-15
    • 1970-01-01
    • 2020-05-25
    相关资源
    最近更新 更多