【问题标题】:Search function - logic in the wrong place搜索功能 - 逻辑在错误的地方
【发布时间】:2015-09-08 08:51:38
【问题描述】:

我正在其他人设置的应用上实现基本搜索功能。有 3 个表 BookingRoomHost,搜索功能需要向用户询问 3 个字段:start_dateend_datenumber_of_guests

搜索需要返回在该时间段内有可用房间的房东列表(start_date/end_date 参数)以及同一房间内的客人数量,显示在该时间段内该房东有哪些房间可用,如果有的话的房间已经有客人预订了。

搜索还需要根据他们现有的预订(列在Bookings 表中)确定哪些房东有空,并且需要显示所有有空房的房东,即使房间已部分预订。

我当前的解决方案如下所示。在app/views/search/new.html.erb:

<div class="row search-area">
  <%= form_tag search_index_path, method: :get do %>
  <div class="small-12 medium-1 large-1 columns search-field">
    <%= label_tag "From", nil, class: "right inline" %>
  </div>
  <div class="small-12 medium-2 large-2 columns search-field">
    <%= text_field_tag(:start_date, params[:start_date]) %>
  </div>
  <div class="small-12 medium-1 large-1 columns search-field">
    <%= label_tag "To", nil, class: "right inline" %>
  </div>
  <div class="small-12 medium-2 large-2 columns search-field">
    <%= text_field_tag(:end_date, params[:end_date]) %>
  </div>
  <div class="small-12 medium-1 large-1 columns search-field">
    <%= label_tag "Guests", nil, class: "right inline" %>
  </div>
  <div class="small-12 medium-2 large-2 columns search-field">
    <%= number_field(:number_of_guests, params[:number_of_guests], in: 1.0..20.0, step: 1.0) %>
  </div>
  <div class="small-12 medium-3 large-3 columns">
    <%= submit_tag "Search", name: nil, :class => "button" %>
  </div>
  <% end %>
</div>

search_controller.rb

  def index
    @start_date = Date.parse(params[:start_date])
    @end_date = Date.parse(params[:end_date])
    @guests = (params[:number_of_guests]).first.to_i
    @space = 0

    @bookings = Booking.all
    @hosts = [] # this will store available hosts

    # get all hosts for specified time period
    @bookings.each { |b| @hosts.push(b.room.host) if ((b.start_date >= @start_date &&
      b.start_date <= @end_date) || (b.end_date >= @start_date &&
      b.end_date <= @end_date)) }

    @hosts = @hosts.paginate(page: params[:page], per_page: 5)
  end

app/views/search/index.html.erb:

<div>
<% @hosts.each do |host| %>
  <div class="row">
    <% if host.rooms.any? { |room| room.bookings.empty? } %>
      <!-- if a host has rooms without bookings then they are definitely going to have free rooms -->
      <div class="small-3 medium-4 large-4 columns">
        <%= image_tag host.picture_url %>
      </div>
      <div class="small-9 medium-8 large-8 columns">
        <p>Host #<%= host.id %>: <%= host.name %></p>
        <p><%= host.address %></p>
        <% host.rooms.each do |room| %>
          <!-- display information on free rooms -->
          <% if room.bookings.empty? %>
            <p>room #<%= room.id %> is available (0 booked, <%= room.capacity %> free out of <%= room.capacity %>)</p>
          <% else %>
            <!-- for the rooms with bookings - check if rooms are fully booked first -->
            <% unless ((room.capacity - room.bookings.first.number_of_guests) == 0) %>
              <% total_booked = room.bookings.first.number_of_guests %>
              <% space = room.capacity - total_booked %>
              <p>room #<%= room.id %> is available (<%= total_booked %> booked, <%= space %> free out of <%= room.capacity %>)</p>
            <% end %>
          <% end %>
        <% end %>
      </div>
    <% else %>
    <!-- if all the rooms belonging to a host are booked - check if all the rooms are fully booked -->
      <% if !(host.rooms.all? { |room| (room.capacity - room.bookings.first.number_of_guests) == 0 }) %>
        <!-- If all the rooms are fully booked there is nothing to display so there is no else block. Check the rooms individually for availability -->
        <div class="small-3 medium-4 large-4 columns">
          <%= image_tag host.picture_url %>
        </div>
        <div class="small-9 medium-8 large-4 columns">
          <p>Host #<%= host.id %>: <%= host.name %></p>
          <p><%= host.address %></p>
          <% host.rooms.each do |room| %>
            <% unless ((room.capacity - room.bookings.first.number_of_guests) == 0) %>
              <% total_booked = room.bookings.first.number_of_guests %>
              <% space = room.capacity - total_booked %>
              <p>room #<%= room.id %> is available (<%= total_booked %> booked, <%= space %> free out of <%= room.capacity %>)</p>
            <% end %>
          <% end %>
        </div>
      <% end %>
    <% end %>
  </div>
<% end %>
</div>

我意识到这个解决方案存在很多问题,所以我想问是否有人可以为我指出正确的方向,我需要采取哪些步骤来使此代码符合最佳实践并提高性能/高效的。具体来说:

  1. 我知道为可用房间过滤主机的逻辑不应该在视图文件中,但我不确定如何将其移动到控制器,或者这是否是合适的位置。我正在分解将此代码放在其他地方的逻辑。
  2. 我没有搜索模型,因为我的理解是模型与数据库表相关联,而搜索功能没有。我这样想错了吗?
  3. 视图中有很多重复,我希望当我最终弄清楚逻辑过滤室/主机应该去哪里时,这已经被清除了,但如果没有任何关于干燥视图文件的提示?
  4. 我知道在计算每个房间的可用空间时 - 我只检查该房间的第一次预订。目前每个房间只有 1 个预订,但我知道它不会保持这种状态,实际上我应该检查该房间的所有预订。我没有这样做,因为它与我在根据 start/end_date 参数检索到可用的主机后如何进一步过滤主机的困惑有关。

任何帮助找出使这个更多的 rails/ruby-ist 和更高性能的步骤将不胜感激。

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    将搜索逻辑放在控制器中不是一个好主意,因为您可能希望将来在另一个控制器(例如 API)中重复使用该逻辑,因此我建议您在应用程序中创建一个 services 文件夹目录app/services,您将在其中拥有一个带有search 函数的SearchService 类,该函数接受查询和过滤参数并返回结果。

    对于视图,我建议您将所有逻辑移至其各自的模型中,例如在Host 模型中添加一个检查是否所有房间都已预订的函数host.are_all_rooms_booked?Room 模型添加total_bookings函数等等。

    这样您将拥有一个更简单的视图,并且所有逻辑都将位于模型或服务中,因此可以从应用程序的其他部分重用。

    【讨论】:

    • 感谢有关将逻辑放入单个模型的提示,这似乎真的让事情变得清晰起来。至于服务文件夹,是否在我的应用程序的根目录中执行?然后我可以将该搜索功能链接到 search#index - 我被特别要求实施该操作。
    • services 目录将在您的app 目录app/services 中,您可以在SearchController#index 操作@results = SearchService.search(params[:query], params[:filter]) 中使用SearchService
    • 很高兴我的帮助,如果这回答了你的问题,请接受我的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 2016-04-23
    • 2022-11-15
    相关资源
    最近更新 更多