我按照教程在Ruby on Rails上建立了一个餐厅评论网站,并将其改编为医院。
我想在网格视图中以最高评论或最高评论数量或按位置(数据库中所有可用数据)的排序格式显示数据库中的结果(仅限前六名)。
我不确定从哪里开始,我知道这可能听起来很简单,但我已经研究过,并且看到了很多选项,并对从何处开始感到困惑。 一些解决方案似乎适合小型数据集,但我完全希望它在未来呈指数级增长,因此最有效的方式对我来说是最好的。 我的本地环境中有SQLlite,生产环境中有Postgres。
这就是我在搜索页面上显示的所有医院以及我在索引页面中显示的内容,该页面显示网格中的所有记录。非常感谢任何帮助。
search.html.erb
<div class="table-responsive table-box card">
<%= form_tag search_hospitals_path, method: :get, class: "form-group" do %>
<div class="input-group">
<div class="input-group-addon">Search and Review</div>
<p>
<%= text_field_tag :search, params[:search], class: "form-control formInput", placeholder: "Hospital Name" %>
</p>
</div>
<% end %>
<div class="container hospital_display">
<% @hospitals.each do |hospital| %>
<div class="row">
<div class="col-sm-6">
<%= link_to image_tag(hospital.image), hospital, class: "responsive" %>
</div>
<div class="col-sm-6">
<%= link_to hospital.name, hospital %><br>
<%= hospital.address %><br>
<%= hospital.phone %><br>
<%= link_to hospital.website, hospital.website %>
<%# Checks for admin %>
<% if user_signed_in? && current_user.admin? %>
<%= link_to 'Edit', edit_hospital_path(hospital), class: "btn btn-link" %>
<%= link_to 'Destroy', hospital, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-link" %>
<% end%>
<%# Rating %>
<% if hospital.reviews.count == 0 %>
No reviews yet, be the first to write one
<% elsif hospital.reviews.count == 1 %>
<div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
1 Review
<% else %>
<div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
<%= hospital.length %> <%= "Reviews" %>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
<br>
<script>
$('.star-rating').raty({
path: 'https://s3-us-west-2.amazonaws.com/morafamedapp/stars',
readOnly: true,
score: function() {
return $(this).attr('data-score');
}
});
</script>
我在索引页面上有这个 的 index.html.erb
<div class="jumboFluid">
<div class="jumbotron">
<section class="content">
<%= form_tag search_hospitals_path, method: :get, class: "form-group" do %>
<div class="input-group">
<div class="input-group-addon">Search</div>
<p>
<%= text_field_tag :search, params[:search], class: "form-control formInput", placeholder: "Eye, Maternity" %>
<%# <%= submit_tag "Search", name: nil, class: "btn btn-default" %>
</p>
</div>
<% end %><br>
<h3 class="intro2">Find the best HealthCare Options around you with Medapp.
<br><%# Explore the best of healthcare available in your community.<br>
Read and leave reviews to assist others seeking the best health care and keep our hospitals on their toes. %></h3>
</section>
</div>
</div>
<div class="hospitalList">
<h1 id="hospitalBanner">Hospitals</h1>
<blockquote>
<p class="text-center"><cite>“Explore the best of healthcare available in your community”</cite> </p>
</blockquote>
<% content_for(:body_attributes) do %>
data-no-turbolink="false"
<% end %>
<main>
<div class="container-fluid fluid">
<div class="row">
<% @hospitals.each do |hospital| %>
<div class="col-md-4 col-xs-6">
<div class="thumbnail">
<%= link_to image_tag(hospital.image), hospital %>
<div class="caption">
<h4> <%= link_to hospital.name, hospital %></h4><br>
<% if hospital.reviews.count == 0 %>
0 Reviews
<% elsif hospital.reviews.count == 1 %>
<div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
1 Review
<% else %>
<div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
<%= hospital.length %> <%= "Reviews" %>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</main>
<br>
<% if user_signed_in? && current_user.admin? %>
<%= link_to 'New Hospital', new_hospital_path, class: "btn btn-primary btn-lg btn-special" %>
<% end %>
<!--Start of Tawk.to Script-->
<script type="text/javascript">
window.$_Tawk = undefined;
var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
(function(){
var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
s1.async=true;
s1.src='https://embed.tawk.to/592da976b3d02e11ecc677a1/default';
s1.charset='UTF-8';
s1.setAttribute('crossorigin','*');
s0.parentNode.insertBefore(s1,s0);
s1.style.background = 'yellow';
})();
</script>
<!--End of Tawk.to Script-->
<script>
$('.star-rating').raty({
path: 'https://s3-us-west-2.amazonaws.com/morafamedapp/stars',
readOnly: true,
score: function() {
return $(this).attr('data-score');
}
});
</script>
</div>
Hospitals_controller.rb
class HospitalsController < ApplicationController
before_action :set_hospital, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:search, :index, :show]
before_action :check_user, except: [:search, :index, :show]
protect_from_forgery with: :null_session
protect_from_forgery except: ["create"]
def search
if params[:search].present?
@hospitals = Hospital.search(params[:search])
else
@hospitals = Hospital.all
end
end
def import
Hospital.import(params[:file])
end
# GET /hospitals
# GET /hospitals.json
def index
@hospitals = Hospital.all
end
# GET /hospitals/1
# GET /hospitals/1.json
def show
@reviews = Review.where(hospital_id: @hospital.id).order("created_at DESC")
if @reviews.blank?
@avg_rating = 0
else
@avg_rating = @reviews.average(:rating).round(2)
end
end
# GET /hospitals/new
def new
@hospital = Hospital.new
end
# GET /hospitals/1/edit
def edit
end
# POST /hospitals
# POST /hospitals.json
def create
import if params[:file] # <= this here is the call to your import method
@hospital = Hospital.new(hospital_params)
respond_to do |format|
if @hospital.save
format.html { redirect_to @hospital, notice: 'Hospital was successfully created.' }
format.json { render :show, status: :created, location: @hospital }
else
format.html { render :new }
format.json { render json: @hospital.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /hospitals/1
# PATCH/PUT /hospitals/1.json
def update
respond_to do |format|
if @hospital.update(hospital_params)
format.html { redirect_to @hospital, notice: 'Hospital was successfully updated.' }
format.json { render :show, status: :ok, location: @hospital }
else
format.html { render :edit }
format.json { render json: @hospital.errors, status: :unprocessable_entity }
end
end
end
# DELETE /hospitals/1
# DELETE /hospitals/1.json
def destroy
@hospital.destroy
respond_to do |format|
format.html { redirect_to hospitals_url, notice: 'Hospital was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_hospital
@hospital = Hospital.find(params[:id])
end
def check_user
unless current_user.admin?
redirect_to root_url, alert: "Sorry, only admins can do that!"
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def hospital_params
params.require(:hospital).permit(:name, :address, :city_town, :state, :phone, :website, :safe_care, :jci, :cohsasa, :best_known_4, :image )
end
end
答案 0 :(得分:0)
如果您不关心访问该值本身,只想要我建议使用andrew21s answer的订单。有了这个,让我们回答。
这个问题很简单,虽然答案比你想象的要复杂得多。我假设模型中有以下关联:
class Hospital < ApplicationRecord
has_many :reviews
end
class Review < ApplicationRecord
belongs_to :hospital
end
通过以上目前,可以通过以下范围解决此问题:
class Hospital < ApplicationRecord
# ...
def self.include_review_count
review_count = Review.select(Review.arel_table[:id].count)
.where(Review.arel_table[:hospital_id].eq(arel_table[:id]))
.as('review_count')
select(*attribute_names.map(&:to_sym)).select(review_count)
end
def self.include_review_average
review_average = Review.select(Review.arel_table[:rating].average)
.where(Review.arel_table[:hospital_id].eq(arel_table[:id]))
.as('review_average')
select(*attribute_names.map(&:to_sym)).select(review_average)
end
# ...
end
有了这些范围,您现在可以在控制器中执行以下操作:
class HospitalsController < ApplicationController
# ...
def index
@hospitals = Hospital.include_review_count
.include_review_average
.order('review_count DESC', 'review_average DESC', :id)
.limit(6)
end
# ...
end
注意:在上面的代码中,您无法使用
.order(review_count: :desc, review_average: :desc, id: :asc)
,因为“review_count”不是真正的属性,而只是一个别名。因此,您必须使用文字(String)变体。在 where 语句中使用此添加的属性时也是如此。例如:.where(review_count: 2)
不起作用,而.where('review_count = ?', 2)
确实起作用。
此解决方案只进行一次查询,并允许您访问值而无需其他查询。一个例子可能是(index.html.erb):
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Review Count</th>
<th>Review Average</th>
</tr>
</thead>
<tbody>
<% @hospitals.each do |hospital| %>
<tr>
<td><%= hospital.id %></td>
<td><%= hospital.name %></td>
<td><%= hospital.review_count %></td>
<td><%= hospital.review_average %></td>
</tr>
<% end %>
</tbody>
</table>