Contare child rows per un determinato record.
Supponiamo il caso di avere un post con relativi articoli, un autore con molti libri, una ditta che ha ricevuto degli ordini, o ancora, un la risposta piu' votata all'interno di un questionario.
In tutti questi casi, per ogni record principale avremo piu' record correlati. Supponiamo il caso di voler contare, nella pagina dove vengono elencate le risposte, quanti voti ogni risposta ha ricevuto, mostrando la piu' votata per prima. In Rails, possiamo scrivere un apposito metodo direttamente nel model.
class Answer < ActiveRecord::Base belongs_to :survey has_many :vote, :dependent => :destroy def self.more_voted(survey_id) voted_answer = find( :all, :select => 'answers.*, count(votes.id) as vote_count', :conditions => ["answers.survey_id = ?", survey_id], :joins => 'left outer join votes on votes.answer_id = answers.id', :group => 'answers.id', :Order => 'vote_count DESC' ) end end
Ora nella nostra action 'show' per il controller survey, dove vengono elencate tutte le risposte per il tal survey, possiamo recuperare le answer con il metodo appena creato.
@answers = Answer.more_voted(params[:survey_id])
e mostrare nella view il valore 'vote_count'
<% @answers.each do |a| %>
<tr class="even">
<td><%= "#{a.reply}" %></td>
<td><%= "#{a.vote_count}" %> </td>
</tr>
<% end %>
Link consigliati:
http://therailsway.com/2007/6/1/railsconf-recap-skinny-controllers
http://blog.devinterface.com/2010/06/rails-best-practices-1-fat-model-skinny-controller/
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
Aggiungere una action ad un controller in rails3
Rails3 cread i default sette azioni per ogni controller generato dinamicamente.
Se vogliamo aggiungere un azione, che ne so, per aggiornare un solo valore nel database, per una nuova view, o per quasiasi altra cosa, dobbiamo:
1)Scrivere la nostra azione nel controller, in questo esempio scrivero' un azione per disapprovare un commento, settando a "0" il valore del campo "approved".
def disapprove
@comment = Comment.find(params[:id])
if ( @comment.update_attribute(:approved, "0"))
respond_to do |format|
format.html { redirect_to(admin_comment_url(@comment),
:notice => 'Comment was unapproved.') }
format.xml { head:ok }
end
else
respond_to do |format|
format.html { render :action => "edit" }
format.xml {render:xml=>@comment.errors, :status => :unprocessable_entity }
end
end
end
Nel mio file routes.rb, dovro' dire alla mia app che oltre alle 7 azioni canoniche ce ne' un altra, disapprove. E dovro' specifivare che tipo di http request e', tra post, get, put e delete. Nel mio caso ho messo post, piu' dettagli qui
resources :comment do post 'disapprove',:on=>:member end
Lanciando "rake routes" nella cartella della mia app, posso vedere la nuova route creata, e vedere quale e' l'url da utlizzare nell'helper. Nel mio caso l'approvazione dei commenti si trova nell'admin area.
disapprove_admin_comment POST /admin/comments/:id/disapprove(.:format) {:controller=>"admin/comments", :action=>"disapprove"}
Ora creaimo un link all'azione
<%= link_to 'Disapprove', disapprove_admin_comment_path(@comment)%>
Dopo aver generato questo link, ottenevo un errore "No route matches..." la mia azione.
Errore risolto specificando nel link il tipo di http verb
<%= link_to 'Disapprove', disapprove_admin_comment_path(@comment), :method=>'post' %>
Consiglio questi screencast, per capire come vengono generate le routes, 1 e 2
Creare un admin area in rails3 usando l’autenticazione scritta in devise
1)aggiungere il namespace "admin" in routes.rb, ed abbinarlo ai controller per i quali vogliamo l'autenticazione, in questo esempio "questions".
namespace :admin do match '/' => 'questions#index' resources :questions end
2In views/layout creare il layout admin.html.erb specificando le parti che vogliamo mostrare nella sezione admin.
3) creare il controller admin_controller.rb in controllers/admin e utilizzare "autenticate_user" (vedere il tutorial su devise) per verificare che un utente sia loggato
class Admin::AdminController < ApplicationController layout "admin" before_filter :authenticate_user! end
4) Sempre in controllers/admin, creare il file questions_controller.rb
class Admin::QuestionsController < Admin::AdminController
def index
@questions = Question.all
respond_to do |format|
format.html # index.html.erb
end
end
end
5)in views/admin creaimo la cartella "questions" e inderiamo tutte le views richieste dal controller controllers/admin/questions_controller.rb, in questo caso, solo il file index.html.rb
6
Le action dei form all'interno delle views in views/admin/questions devono rimandare ai controllers in controllers/admin/question controller. Quindi, sempre tenendo "question" come esempio da:
<%= form_for(@answer) do |f| %>
dobbiamo passare a
<%= form_for(:admin, @answer) do |f| %>