如何加入数据?

How can I join data?


我正在制作一个搜索条件页面。

我要的是,如果有多个条件搜索&&,如果有空白字段,搜索不包括空白字段。

我当前的代码是:

    name_sei = params[:nameSei]
    name_mei = params[:nameMei]
    email = params[:email]
    tel = params[:tel].to_i
    birth = params[:birth].to_i
    job_area = params[:jobArea]
    station = params[:station]
    sex = params[:sex]
    coordinator = params[:coordinator]
    inflow_souce = params[:inflowSouce]
    evaluation = params[:evaluation] || []
    skill = params[:skill] || []
    position = params[:position] || []

      users =
        User
          .order('users.created_at DESC')
          .includes(:evaluations, :skills, :positions)
          .where('name_sei like ?', "%#{name_sei}%" && 'name_mei like ?', "%#{name_mei}%" && 'email like ?', "%#{email}%"....)

我的代码的问题是,如果该字段包含空白,rails 将包含 "" 并且搜索将失败。

所以我想出了这个代码:

      users =
        User
          .order('users.created_at DESC')
          .includes(:evaluations, :skills, :positions)
          .where('name_sei like ?', "%#{name_sei}%") if params[:nameSei] != ''

      users =
        User
          .order('users.created_at DESC')
          .includes(:evaluations, :skills, :positions)
          .where('name_mei like ?', "%#{name_mei}%") if params[:nameMei] != ''

我觉得如果那两个用户数据能join就好了。
但我不知道如何加入数据。
你能帮帮我吗?

谢谢。

与其在控制器中“内联”搜索功能,不如将其移出到单独的模型中:

# app/models/user_search.rb
# This is just a model to represent a search query
# its not actually saved to the database
class UserSearch
  include ActiveModel::Model
  include ActiveModel::Attributes

  # @see https://api.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html
  attribute :name_sei
  attribute :name_mei
  attribute :tel,   :integer   
  attribute :birth, :integer   # Use a date instead?
  attribute :sex
  # ... define the rest of the attributes you want to be able to filter by

  # This just loops through the attributes of this model and 
  # filters the users based on it
  # blank attributes are filtered out
  # 
  # this will filter the results by using `WHERE x = y`
  # you can easily override it on a per attribute basis by 
  # implementing a `filter_by_x` method
  # that method should return a ActiveRecord::Relation or nil
  # @param [ActiveRecord::Relation] base
  # @return [ActiveRecord::Relation] the base scope with filters applied
  def to_scope(base: User.all)
    scopes = attributes.compact_blank do |attr, value|
      if respond_to?("filter_by_#{attr}")
        send("filter_by_#{attr}", value)
      else
        User.where(attr => value)
      end
    end
    scopes.compact.inject(base) {|memo, item| memo.merge(item)}
  end

  private

  def filter_by_name_sei(val)
    User.where('"users"."name_sei" like ?', "%#{val}%")
  end

  def filter_by_name_mei(val)
    User.where('"users"."name_mei" like ?', "%#{val}%")
  end
end

这让您可以通过将搜索过滤器的散列传递给 class 来测试它的隔离,而不是创建一个完整的 HTTP 请求,然后编写关于来自控制器的响应的断言。您不必一定要将此功能放入模型中 - 这里的关键要点是不要只是将它放入您的控制器中,因为这将非常难以测试。

使用模型确实可以让您使用 ActiveModel 的所有优点,例如类型转换、默认值、验证、I18n 集成等

从您的控制器中,您可以使用强参数将参数传递给模型:

class UsersController
  # GET /users
  # GET /users?search[name_sei]=foo...
  def index
    @search = UserSearch.new(search_parameters)
    @users = @search.to_scope(base: User.order(created_at: :desc))
  end

  private

  def search_parameters
    params.fetch(:search, {})
          .permit(
            :name_sei, :name_mei # ...
          )
  end
end

您只需创建一个绑定到模型的表单即可:

<%= form_with(model: @search, url: users_path, method: :get, scope: :search) do |form| %>
  <div class="field">
    <%= f.label :name_sei %>
    <%= f.text_field :name_sei %>
  </div>

  # ...

  <div class="actions">
    <%= f.submit "Search" %>
  </div>
<% end %>