Ruby for Rails best practice sixteen

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

The sixteenth chapter to improve the controller and view

Controller action and the corresponding template to summarize second version of the R4RMusic
The controller
Description
Action method
The main template
Customer
Sign in
Cancellation
Register a new account
Add a version to the shopping cart
View the shopping cart
Checkout (purchased completed)
login
logout
signup
add_to_cart
view_cart
check_out
main/welcome.rhtml
main/welcome.rhtml
main/welcome.rhtml
customer/view_cart.rhtml
customer/view_cart.rhtml
customer/check_out.rhtml
Main
Welcome visitor
Display all the given time work
welcome
show_period
main/welcome.rhtml
main/show_period.rhtml
Composer
Display all versions of a composer's works
show
composer/show.rhtml
Edition
Display version of the detailed publication information
show
edition/show.rhtml
Instrument
Display all given musical works
show
instrument/show.rhtml
Work
Display all versions of a given work
show
work/show.rhtml
R4RMusic final version download: http://kerryas.googlecode.com/files/r4rmusic.rar

A view template definition, as auxiliary method

The 1 auxiliary method to organize and Access Custom
In the app/helper directory for the auxiliary file for each controller_helper.rb controller, for example, composer_helper.rb contains the following contents
module ComposerHelper
end
The method definition to the auxiliary file can help to reduce duplication of code, you can write an automatically generated links auxiliary method
module ComposerHelper
def link_to_composer(composer)
link_to (composer.whole_name,
:controller => "composer",
:action => "show",
:id => composer.id)
end
end
Here is how to use the new link_to_composer method in the template example
<ul>
<% @composers.each do |composer| %>
<li><%= link_to_composer(composer) %></li>
<% end %>
</ul>

Method of use of other auxiliary files in
Method: the controller assisted method, the method is declared as a helper, for example
class MainController <ApplicationController
helper :composer
# etc.
end

Method two: the auxiliary file into universal auxiliary file application_helper.rb, so the controller and the template all these methods are visible.

2 for the R4RMusic customization method

Method
Defined on
To include these controller through helper
link_to_composer
link_to_work

link_to_edition
link_to_edition_title
link_to_instrument
two_dec
composer_helper.rb
work_helper.rb

edition_helper.rb
edition_helper.rb
instrument_helper.rb
application_helper.rb
customer, edition, main
composer, customer, edition, instrument, main
customer, work
composer, instrument
main
Be all controller access


Here is the definition of the first five auxiliary method:
def link_to_composer(composer)
link_to(composer.whole_name,
:controller => "composer",
:action => "show",
:id => composer.id)
end

def link_to_edition(edition)
link_to edition.description,
:controller => "edition",
:action => "show",
:id => edition.id
end

def link_to_edition_title(edition)
link_to edition.nice_title,
:controller => "edition",
:action => "show",
:id => edition.id
end

def link_to_work(work)
link_to(work.nice_title,
:controller => "work",
:action => "show",
:id => work.id)
end

def link_to_instrument(instrument)
link_to instrument.name,
:controller => "instrument",
:action => "show",
:id => instrument.id
end

The sixth auxiliary method will be a floating point number is converted to a two decimal string
module ApplicationHelper
def two_dec(n)
sprintf("%.2f", n)
end
end

The two part, coding and deployment view template

1 Analysis of main template
First check the composer/show.html.erb template file
<% @page_title = "Editions of works by #{@composer.whole_name}" %>

<h2 class="info"><%= @page_title %></h2>
<p>Click on any edition to see details.</p>
<%= render :partial => "editions" %>

The render method to examine the part template name, add a underscore in front of it, add a.Html.erb suffix behind it, here is composer/_editions.html.erb
<ul>
<% @composer.editions.map do |edition| %>
<li><%= link_to_edition_title(edition) %>
(<%= edition.publisher.name %>, <%= edition.year %>)</li>
<% end %>
</ul>

2 in the popular view template using partial template
(1)Generate a list of links to the composer
Create a list of links to composer composer/_list.html.erb
<ul>
<% @composers.each do |composer| %>
<li><%= link_to_composer(composer) %></li>
<% end %>
</ul>

Will this line in the main template in main/welcome.html.erb
<%= render :partial => "composer/list" %>

(2)A list of links to generate musical instruments
Part of the template instrument/_list.html.erb
<ul>
<% @instruments.each do |instrument|%>
<li><%= link_to_instrument(instrument) %></li>
<% end %>
</ul>

Create a instrument controller:
F:\ruby_project\R4Rmusic>ruby script/generate controller instrument show

To complete the instrument_controller.rb file:
class InstrumentController <ApplicationController
helper :work, :edition
def show
@instrument = Instrument.find(params[:id])
end
end

(3)Generate a list of links to Music Era
Generate a list of links to main Music Era/_period_list.html.erb
<ul>
<% @periods.each do |period| %>
<li><%= link_to period,
:controller => "main",
:action => "show_period",
:id => period %>
<% end %>
</li>
</ul>

We also need to add some template in the welcome template
<%= render :partial => "period_list" %>

(4) Complete welcome template(views/main/welcome.html.erb)
<% if @c %>
<h3>Welcome, <%= @c.first_name %>.</h3>
<% end %>
<h2 class="info">Browse works by...</h2>

<table>
<tr>
<th>...Period</th>
<th>...Composer</th>
<th>...Instrument</th>
</tr>
<tr>
<td>
<%= render :partial => "period_list" %>
</td>
<td>
<%= render :partial => "composer/list" %>
</td>
<td>
<%= render :partial => "instrument/list" %>
</td>
</tr>
</table>

<% if @c %>
<%= render :partial => "favorites" %>
<% else %>
<h2 class="info">Log in or create an account</h2>
<table border="1">
<tr>
<th>Log in to your account</th>
<th>Sign up for an account</th>
</tr>
<tr>
<td><%= render :partial => "customer/login" %></td>
<td><%= render :partial => "customer/signup" %></td>
</tr>
</table>
<% end %>

Three, update the master controller

The Welcome action of new faces(main_controller.rb):
class MainController <ApplicationController
helper :work, :composer, :instrument

def welcome
@composers = Composer.find(:all).sort_by do |composer|
[composer.last_name, composer.first_name, composer.middle_name]
end
@periods = Work.all_periods
@instruments = Instrument.find(:all, :order => "name ASC" )
end

def show_period
@period = params[:id]
works = Work.find(:all).select do |work|
(work.period == @period) || (work.century == @period)
end
@editions = Edition.of_works(works)
end

end

Four, to join the customer registration login action

1 login and registration template
(1)Register template customer/_signup.html.erb
<% form_tag :controller => "customer",
:action => "signup" do %>
<p>First name: <%= text_field "customer", "first_name" %> </p>
<p>Last name: <%= text_field "customer", "last_name" %> </p>
<p>User name: <%= text_field "customer", "nick" %> </p>
<p>Password: <%= password_field "customer", "password" %> </p>
<p>Email address: <%= text_field "customer", "email" %> </p>
<p><input type="Submit" value="Sign up"/></p>
<% end %>

(2)Login template customer/_login.html.erb
<% form_tag :controller => "customer",
:action => "login" do %>
<p>User name: <%= text_field "customer", "nick" %></p>
<p>Password: <%= password_field "customer", "password" %></p>
<p><input type="Submit" value="Log in"/></p>
<% end %>

The 2 sign and save the session state
def login
pw,nick = params[:customer].values_at(*%w{password nick})
c = Customer.find_by_nick(nick)
if c && Digest::SHA1.hexdigest(pw) == c.password
@session['customer'] = c.id
redirect_to :controller => "main", :action => "welcome"
else
report_error("Invalid login")
end
end

3 using before_filter watch movements(ApplicationController.rb)
class ApplicationController <ActionController::Base
layout("base")

before_filter :get_customer

def get_customer
if session['customer']
@c = Customer.find(session['customer'])
end
end
end

If the user's ID has saved in session, then the database can find out the object @c is not empty, otherwise the @c is empty, the main interface display prompts the user login:
<% if @c %>
<%= render :partial => "favorites" %>
<% else %>
<h2 class="info">Log in or create an account</h2>
#
# display of login and signup forms handled here
#
<% end %>

We also hope to intercept the requested action filter can not log in customer case(CustomerController.rb)
before_filter :authorize, :except => ["signup","login"]
def authorize
return true if @c
report_error("Unauthorized access; password required")
end
The report_error is an error report method through the self-made,, is defined in the application.rb
class ApplicationController <ActionController::Base
# prior code here, then:
private
def report_error(message)
@message = message
render("main/error")
return false
end
end
The incoming message to Fu value @message instance variables, present in the app/views/main/error.html.erb

4 the implementation of the registration function(CustomerController.rb)
def signup
c = Customer.new(params[:customer])
c.password = Digest::SHA1.hexdigest(c.password)
c.save
session['customer'] = c.id
redirect_to :controller => "main", :action => "welcome"
end

The use of before_filter technology, verification form data, create a new_customer filter, only let it before the signup action as a filter to perform
before_filter :new_customer, :only => ["signup"]

def new_customer
applicant = params[:customer]
if Customer.find_by_nick(applicant['nick'])
report_error("Nick already in use. Please choose another.")
elsif Customer.find_by_email(applicant['email'])
report_error("Account already exists for that email address")
end
end

5 to prepare customer logoff scripts (join the logout button, in app/view/layout/base.html.erb and in body)
<table>
<tr>
<td><%= link_to "Home",
:controller => "main",
:action => "welcome" %></td>
<% if @c %>
<td><%= link_to "View cart",
:controller => "customer",
:action => "view_cart" %></td>
<td><%= link_to "Log out",
:controller => "customer",
:action => "logout" %></td>
<% end %>
</tr>
</table>

Five, deal with customer orders

The first is app/controllers/customer_controller.rb add an action
def view_cart
end

And then the realization of view_cart.html.erb view
<% @page_title = "Shopping cart for #{@c.nick}" %>
<%= render :partial => "cart" %>

The following is the shopping cart view customer/_cart.html.erb part template
<table border="1">
<tr>
<th>Title</th>
<th>Composer</th>
<th>Publisher</th>
<th>Price</th>
<th>Copies</th>
<th>Subtotal</th>
</tr>

<% @c.editions_on_order.each do |edition| %>
<% count = @c.copies_of(edition) %>
<tr>
<td><%= link_to_edition_title(edition) %></td>
<td>
<% edition.composers.each do |composer| %>
<%= link_to_composer(composer) %>
<% end %></td>
<td><%= edition.publisher.name %></td>
<td class="price"><%= two_dec(edition.price) %>
<td class="count"><%= count %></td>
<td class="price"><%= two_dec(edition.price * count) %></td>
</tr>
<% end %>
<tr><td colspan="5">TOTAL</td>
<td class="price"><%= two_dec(@c.balance) %></td>
</tr>
</table>
<p><%= link_to("Complete purchases",
:controller => "customer",
:action => "check_out") %></p>

2 see and buy a version
The main template view version, edition/show.html.erb
<% @page_title = @edition.nice_title %>
<h2 class="info"><%= @page_title %></h2>
<%= render :partial => "details" %>

Partial template view version, edition/_details.html.erb template
<ul>
<li>Edition: <%= @edition.description %></li>
<li>Publisher: <%= @edition.publisher.name %></li>
<li>Year: <%= @edition.year %></li>
<li>Price: <%= two_dec(@edition.price) %></li>
<% if @c %>
<li><%= link_to "Add to cart",
:controller => "customer",
:action => "add_to_cart",
:id => @edition.id %></li>
<% end %>
</ul>
<h3>Contents:</h3>
<ul>
<% @edition.works.each do |work| %>
<li><%= link_to_work(work) %> (<%= link_to_composer(work.composer) %>)</li>
<% end %>
</ul>

3 definition of add_to_cart action(CustomerController.rb)
def add_to_cart
e = Edition.find(params[:id])
order = Order.create(:customer => @c,
:edition => e)
if order
redirect_to :action => "view_cart"
else
report_error("Trouble with saving order")
end
end

4 orders
Defined in the CustomerController.rb
def check_out
@c.check_out
end

Then define app\views\customer\check_out.html.erb as a settlement to complete the view, as follows
<% @page_title = "Orders complete" %>
<h2>Thanks for your order, <%= @c.first_name %>!</h2>

Six, the dynamic code to the page of humanity

1 from the rankings to preferences
Defined in the app/models/customer.rb
def rank(list)
list.uniq.sort_by do |a|
list.select {|b| a == b }.size
end.reverse
end

def composer_rankings
rank(edition_history.map {|ed| ed.composers }.flatten)
end

def instrument_rankings
rank(work_history.map {|work| work.instruments }.flatten)
end

def favorites(thing,options)
limit = options[:count]
rankings = send("#{thing}_rankings")
return rankings[0,limit].compact
end
The favorites method based on the dynamic parameters of thing user preferences, given count to select an entry corresponding array. If the value the rankings than the method returns an array of size, then nil is filled, the last compact will delete these nil.

The characteristics of favorites 2 in practical use
Finally, let us to realize the main/_favorites.html.erb template
<h2 class="info">Your favorites</h2>
<% fav_composers = @c.favorites :composer,
:count => 3 %>
<% fav_instruments = @c.favorites :instrument,
:count => 3 %>
<ul>
<% fav_composers.each do |composer| %>
<li><%= link_to_composer(composer) %></li>
<% end %>
<% fav_instruments.each do |instrument| %>
<li><%= link_to_instrument(instrument) %></li>
<% end %>
</ul>
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Vic at December 23, 2013 - 2:30 PM