4

我是Rails的新手,並正在進行面試工作測試。Activerecord rails合併多個選擇結果並渲染行中的視圖

幾乎達到了預期的結果,下面你可以找到代碼。數據的

實施例:

Bookings 
id,room_id,start_date,end_date,number_of_guests 
1,1,2015-06-01,2015-06-07,1 
2,3,2015-06-01,2015-06-07,2 
3,5,2015-06-01,2015-06-07,2 
2001,6,2015-06-01,2015-06-07,2 
... 

Hosts 
id,name,address 
1,Mr Host 1,1 Camden 
2,Mr Host 2,2 Camden Street 
3,Mr Host 3,3 Camden Street 
4,Mr Host 4,4 Camden Street 
... 

Rooms 
id,host_id,capacity 
1,1,2 
2,1,2 
3,2,2 
4,2,2 
... 

的ActiveRecord:

class Room < ActiveRecord::Base 
    belongs_to :host 
    has_many :bookings 
end 

class Host < ActiveRecord::Base 
    has_many :rooms 
end 

class Booking < ActiveRecord::Base 
    belongs_to :room 
end 

控制器:

start_date = '2015-06-01' # hardcoded value for testing purposes 
    end_date = '2015-06-07' # hardcoded value for testing purposes 

    @available_rooms = Room.select(:host_id, :name, :address, :id, :number_of_guests ,:capacity) 
       .joins(:bookings, :host) 
       .where("bookings.number_of_guests <> rooms.capacity 
         AND ? < rooms.capacity 
         AND ? <= bookings.start_date 
         AND ? <= bookings.end_date", params[:guests], start_date, end_date) 

    @booked_rooms = Room.select(:host_id, :name, :address, :id, :number_of_guests, :capacity) 
       .joins(:bookings, :host) 

    @total_rooms = Room.select(:host_id, :name, :address, :id, "0 as number_of_guests", :capacity) 
       .joins(:host) 

    @rooms = ((@total_rooms - @booked_rooms) + @available_rooms).sort_by(&:id) 

檢視:

<% if @rooms %> 
<section class="rooms"> 
<ul class="list-unstyled list-rooms"> 
    <% for room in @rooms %> 
    <li class="clearfix"> 
    <article> 
     <div class="description"> 
     <header> 
      <h2>host#<%= "#{room.host_id}: #{room.name}" %></h2> 
      <h3><%= "#{room.address} "%></h3> 
     </header> 
     <p>room#<%= "#{room.id} is available (#{room.number_of_guests} booked, #{room.capacity - room.number_of_guests} free out of total #{room.capacity})" %></p> 
     </div> 
    </article> 
    </li> 
    <% end %> 
</ul> 
</section> 
<% end %> 

當前結果:

host#1: Mr Host 1 
    1 Camden Street 
    room#1 is available (1 booked, 1 free out of 2 total) 

    host#1: Mr Host 1 
    1 Camden Street  
    room#2 is available (0 booked, 2 free out of 2 total) 

    host#2: Mr Host 2 
    2 Camden Street 
    room#4 is available (0 booked, 2 free out of 2 total) 

    host#4: Mr Host 4 
    4 Camden Street 
    room#8 is available (0 booked, 2 free out of 2 total) 

    host#5: Mr Host 5 
    5 Camden Street 
    room#9 is available (1 booked, 1 free out of 2 total) 

    host#5: Mr Host 5 
    5 Camden Street 
    room#10 is available (0 booked, 2 free out of 2 total) 

預期結果:

host#1: Mr Host 1 
    1 Camden Street 
    room#1 is available (1 booked, 1 free out of 2 total) 
    room#2 is available (0 booked, 2 free out of 2 total) 

    host#2: Mr Host 2 
    2 Camden Street 
    room#4 is available (0 booked, 2 free out of 2 total) 

    host#4: Mr Host 4 
    4 Camden Street 
    room#8 is available (0 booked, 2 free out of 2 total) 

    host#5: Mr Host 5 
    5 Camden Street 
    room#9 is available (1 booked, 1 free out of 2 total) 
    room#10 is available (0 booked, 2 free out of 2 total) 

我想使用jQuery來獲得期望的結果,但必須有我的方式通過活動記錄實現這一目標,或致電某種視野中的助手。提前致謝。

理想情況下,我想重寫查詢檢索類似下面一行的結果:

host_id, address, total_rooms, room_id[0], booked[0], capacity[0], ... , room_id[n], booked[n], capacity[n] 

所以對於前兩行我們將有:

1, 1 Camden Street, 2, 1, 1, 2, 2, 0, 2 
    2, 2 Camden Street, 1, 4, 0, 2 

相當於前端結果:

主持人1:Mr Host 1 1 Camden Street 有房可提供(1預訂,1間客房總數中有1) 房間#2可用(0黃牌警告,2罰共有2)

主機#2:先生主機2 2卡姆登大街 房間#4可用(0黃牌警告,2罰共有2)

+0

也許你可以寫的問題是什麼?可以更深入地瞭解如何回答這個問題。 – 2015-04-07 12:35:28

回答

6

您不能在SQL級別執行此操作。 SQL返回的是統一行,您可以按照自己喜歡的順序對其進行排序,但分組中的行無法以此方式工作。您不能使用它返回部分行以獲得一對多關係;它將返回每行的完整連接記錄。

如果您想要輸出頂級記錄(本例中爲「主機」)一次,然後多次輸出相關記錄(「房間」),則需要將結果分組到前端:

#... 
@rooms = ((@total_rooms - @booked_rooms) + @available_rooms).sort_by(&:id) 

# Produce a mapping of hosts to their rooms 
@rooms_by_host = @rooms.group_by do |room| 
    { id: host_id, address: room.address, name: room.name } 
end 

group_by將爲其返回相同值的組元素。在這種情況下,任何具有相同host_id,addressname的房間將在返回的散列內組合爲一個嵌套數組。

而且在你看來,你現在將有兩個循環:一個外環,超過主機=>間的映射,併爲每個主機的內部循環,循環在他們的房間迭代:

<section class="rooms"> 
    <ul class="list-unstyled list-rooms"> 
    <% @rooms_by_host.each do |host, rooms| %> 
     <li class="clearfix"> 
     <article> 
      <div class="description"> 
      <header> 
       <h2>host#<%= host[:id] %> - <%= host[:name] %></h2> 
       <h3><%= host[:address] %></h3> 
      </header> 
      <ul class="rooms"> 
       <% rooms.each do |room %> 
       <li>room#<%= room.id %> is available (<%= room.number_of_guests %> booked, <%= room.capacity - room.number_of_guests %> free out of total <%= room.capacity %>)</li> 
       <% end %> 
      </ul> 
      </div> 
     </article> 
     </li> 
    <% end %> 
    </ul> 
</section> 

有兩點要注意,你應該考慮,如果你擔心你如何在面試中展示自己:

  • 不要在Ruby中使用for x in y。循環的慣用方式是y.each do |x|。使用for x in y尖叫經驗不足。
  • <% if @rooms %>是無用的檢查,@rooms是一個數組,它永遠不會是一個虛假的價值。您需要if @rooms.present?if @rooms.any?
  • 請勿同時使用<%= %>"#{...}"。內部#{}是完全多餘的。每次你做了這個地方......

    <%= "#{room.address} "%> 
    

    而應該做到這一點

    <%= room.address %> 
    
  • 它的清潔,讓ActiveRecord的建立儘可能多的SQL越好。取而代之的是...

    .where("bookings.number_of_guests <> rooms.capacity 
              AND ? < rooms.capacity 
              AND ? <= bookings.start_date 
              AND ? <= bookings.end_date", params[:guests], start_date, end_date) 
    

    使用此

    .where('bookings.number_of_guests <> rooms.capacity') 
    .where('? < rooms.capactiy', params[:guests]) 
    .where('? <= bookings.start_date', start_date) 
    .where('? <= bookings.end_date', end_date) 
    

    它也讓你的參數接近他們使用的地方。

  • 如果您想清理一下您的視圖,請使用偏色。最內層的環可以是:

    <ul class="rooms"> 
         <%= render rooms %> 
        </ul> 
    

    和你的循環體移到app/views/rooms/_room.html.erb

    <li>room#<%= room.id %> is available (<%= room.number_of_guests %> booked, <%= room.capacity - room.number_of_guests %> free out of total <%= room.capacity %>)</li> 
    
+0

非常好的答案! – 2015-04-07 13:20:09

+0

作爲魅力,極好的解決方案和最佳實踐提示。 – Sandro 2015-04-07 21:17:42