Фильтр с атрибутом другой таблицы (один ко многим) в Rails

#ruby-on-rails

#ruby-on-rails

Вопрос:

Фильтр с атрибутом другой таблицы (один ко многим) в Rails

Я новичок в rails и в настоящее время работаю над своим классным проектом. У меня есть таблица lead и таблица lead_comments, lead имеет множество lead_comments и lead_comment принадлежат lead, которые я установил.

В модели:

 class Lead < ApplicationRecord
    has_many :lead_comments
end


class LeadComment < ApplicationRecord
    belongs_to :lead
end
  

В представлении индекса моего интереса я пытаюсь настроить фильтр по дате на основе Update_at в lead_comments, который является атрибутом из другой таблицы:

 <div class="date-search">
  <%= form_tag leads_path, method: :get do %>
    <%= date_field_tag 'date_search[date_from]', @date_search.date_from %>
    <%= date_field_tag 'date_search[date_to]', @date_search.date_to %>
    <%= submit_tag 'Date Search' %>
  <% end %>
</div>

<table>
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Phone Number</th>
      <th>Last Updated Date</th>
      <th colspan="3">Action</th>
    </tr>
  </thead>

  <tbody>
    <% @leads.each do |lead| %>
      <tr>
        <td><%= lead.lead_firstname %></td>
        <td><%= lead.lead_lastname %></td>
        <td><%= lead.lead_phone %></td>
        <td><%= lead.lead_comments.maximum(:updated_at) %></td>
        <td><%= link_to 'Detail', lead %></td>
        <td><%= link_to 'Edit/Update', edit_lead_path(lead) %></td>
        <td><%= link_to 'Remove', lead, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>
  

В моем ведущем контроллере я настроил другой контроллер для поиска потенциальных клиентов:

 def index
    @date_search = LeadSearch.new(params[:date_search])
    @leads = @date_search.scope
end
  

В моей модели поиска потенциальных клиентов, я полагаю, в чем моя проблема:

 class LeadSearch
  attr_reader :date_from, :date_to

  def initialize(params)
    params ||= {}
    @date_from = parsed_date(params[:date_from], 30.days.ago.to_date.to_s)
    @date_to = parsed_date(params[:date_to], Date.today.to_s)
  end

  def scope
    Lead.lead_comments.maximum(:updated_at).where('updated_at BETWEEN ? AND ?', @date_from, @date_to)
  end

  private

  def parsed_date(date_string, default)
    Date.parse(date_string)
  rescue ArgumentError, TypeError
    default
  end
end
  

Моя таблица lead_comment имеет только один атрибут, который является комментарием, наряду с двумя автоматизированными атрибутами даты, созданными Rails, created_at и updated_at.

Всякий раз, когда я запускаю приложение, я получаю сообщение об ошибке, которое сообщает мне неопределенный метод «lead_comments». Я думал, что я уже установил отношения has_many и belong_to, и это все еще не работает. Может кто-нибудь, пожалуйста, помочь мне и направить меня в правильном направлении? Спасибо за ваше время.

Ответ №1:

вы выполняете Lead.lead_comments, что неправильно. Вы используете имя класса вместо объекта. Должен быть объект ведущей модели.

 @lead.lead_comments
  

Сначала попробуйте выполнить запрос в консоли rails. затем используйте его в контроллере для лучшей перспективы. попробуйте выполнить следующее,

 Lead.lead_comments # will give error
  

вместо этого используйте,

 Lead.last.lead_comments # success
  

Ответ №2:

Проблемы в вашем коде:

  1. Lead.lead_comments

Давайте упростим это: подумайте о lead_comments как о методе, который, получив преимущество, возвращает свои комментарии. Но нам нужна зацепка. Вот почему вызов на Lead не работает. Это сработало бы, вызванное для Lead объекта.

  1. Lead.lead_comments.maximum(:updated_at)

Здесь вы составляете SQL-запрос, хотя ActiveRecord но вызываете maximum stop this composition, потому что для этого требуется значение, поэтому вы не можете вызывать что-либо еще после таких методов, как maximum

Давайте заставим ваш код работать

 def scope
  Lead.where('updated_at BETWEEN ? AND ?', @date_from, @date_to)
end
  

на ваш взгляд

 <td><%= lead.lead_comments.maximum(:updated_at) %></td>
  

Обратите внимание, что этот код всегда был правильным, потому что вы вызываете lead_comments ведущий объект.

Я знаю, это выполняет один запрос для каждого Lead объекта, но заставить его работать только с одним запросом выглядит как другой вопрос