rails has_many通过where查询

时间:2014-02-27 16:13:43

标签: sql ruby-on-rails forms ruby-on-rails-4

我的模型结构设置如下,

class Conversation < ActiveRecord::Base

  has_many :conversation_statuses, :dependent => :destroy
  has_many :users, :through => :conversation_statuses

  has_many :messages, :inverse_of => :conversation
  accepts_nested_attributes_for :messages
end

class User < ActiveRecord::Base

  has_many :conversation_statuses, :dependent => :destroy
  has_many :conversations, :through => :conversation_statuses

  has_many :messages, :inverse_of => :user

end

class ConversationStatus < ActiveRecord::Base
  belongs_to :user
  belongs_to :conversation
end

我只是在用户没有进行对话时才尝试创建对话。我设置了对话,以便超过2个用户可以进行对话。现在我的查询是查找包括用户ID的对话,但可能包括与大组的对话。我的控制器查询看起来像这样,

class ConversationsController < ApplicationController


before_filter :set_user_ids_param, :only => :create

  def create

    @conversation = Conversation.joins(:users)
                                .where(:users => {:id => params[:conversation][:user_ids]})
                                .first_or_initialize

    @conversation.attributes = conversation_params

    if @conversation.save

      render :json => { :html => render_new_conversation_form }
      return
    end


    render :status => :bad_request, :json => {
      :html => render_conversation_form
    }

  end

  private
    def conversation_params
      params.require(:conversation).permit([
        :user_ids => [],
        :messages_attributes => [
          :content,
          :topic
        ]
      ])
    end

    def set_user_ids_param
      return if params[:conversation].blank?

      return if params[:conversation].blank? || params[:conversation][:user_ids].blank?

      params[:conversation][:user_ids] = params[:conversation][:user_ids].split(',')
      params[:conversation][:user_ids].push(current_user.id)
    end

    def render_new_conversation_form
      render_to_string({
        :partial => 'conversations/form',
        :locals => {
          :conversation => @conversation
        }
      })
    end

    def render_conversation_form
      render_to_string({
        :partial => 'conversations/form',
        :locals => {
          :conversation => @conversation
        }
      })
    end

end

我的表单看起来像这样

= simple_form_for conversation, :html => {:class => 'conversation-form'} do |form|

 = form.input :user_ids, :as => :hidden, :input_html => {:class => 'user-ids'}

  = form.simple_fields_for :messages do |message_fields|
    = render 'messages/fields', :message_fields => message_fields

  %button.button.radius.submit.no-margin
    Send Message

  %button.button.secondary.radius.cancel.no-margin
    Cancel

有关处理此问题的最佳方法的任何想法吗?

1 个答案:

答案 0 :(得分:1)

解决问题的方法应该在课程ConversationStatus中,如果存在,则会为您提供对话的conversation_id

你需要两套:

  • containing_all_users是包含users_id
  • 中所有用户的对话
  • with_extra_users是包含的用户数多于users_id
  • 的用户数

对话(如果存在)是减去这些集合的结果。

class ConversationStatus < ActiveRecord::Base
  belongs_to :user
  belongs_to :conversation

  def self.find_between(user_ids)
    containing_all_users = group(:conversation_id)
        .where(user_id: user_ids)
        .having(['COUNT(user_id) = ?', user_ids.length])
        .pluck(:conversation_id)

    with_extra_users = group(:conversation_id)
        .having(['COUNT(user_id) > ?', user_ids.length])
        .pluck(:conversation_id)

    (containing_all_users - with_extra_users).first
  end
end

您将从Conversation模型中获得对话。您也应该在此方法上设置属性:

class Conversation < ActiveRecord::Base
  has_many :conversation_statuses, dependent: :destroy
  has_many :users, through: :conversation_statuses

  def self.find_between(user_ids, attributes = {})
    conversation_id = ConversationStatus.find_between(user_ids)
    Conversation.where(id: conversation_id).first_or_initialize(attributes)
  end
end

在控制器上你会这样称呼它:

@conversation = Conversation.find_between(params[:conversation][:user_ids],
  conversation_params)