This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA
index.rhtml.erb # file inside app/views/project <% content_for :head do%> #content_for is a helper method <%= stylesheet_link_tag "projects" %> <% end %>
%= stylesheet_link_tag "application" %> <%= yield:head %>
Example: 009_filtering_sensitive_logs Are you accepting sensitive user data? Passwords, credit card numbers, etc. By default, Rails stores all submitted parameters in plain text in the logs. This episode will show you how to filter this sensitive input so it doesn't show up in the log file. application.rb # Filters added to this controller will be run for all controller in the application # Likewise, all the methods added will be available for all controllers class ApplicationController < ActionController::Base filter_parameter_logging “password” #This command will help not to send password in log file. def current_user User.find(session[:user_id]) end
end Example: 010_refactoring_user_name_p1 Learn how to clean up your code through refactoring. This episode will show you how to move code from the view into the model to remove duplication and simplify the view. Show.rhtml.erb
% for user in @users %>
% end %> app/views/profile/show.rhtml.erb
Name: <%= @user.first_name %> <%= “#{@user.middle_initial}.” unless @user.middle_initial.nil? %> <%= @user.last_name %> <%= link_to ‘Users List’ users_path %>
Alternateway
Name: <%= @user.full_name %>
<%= link_to ‘Users List’ users_path %> if user.rb is like below class User < ActiveRecord::Base def full_name name = first_name + “ “ name += “#{middle_initial}. ” Unless middle_initial.nil? name +=last_name name #writing name this way will return name and don’t need to call @user method inside the model end end Now Show.rhtml.erb
% for user in @users %>
% end %> Example: 011_refactoring_user_name_p1 Testing and refactoring go hand in hand. Refactoring is all about improving code without changing its behavior. Testing is all about making sure you don't change the behavior while you are improving the code. user_test.rb require File.dirname(__File__) + ‘/../test_helper’ class UserTest < Test::Unit::TestCase fixtures:users def test_full_name_without_middle_initial user = User.new(:first_name => ‘John’, :last_name => ‘Doe’) assert_equal ‘John Doe’, user.full_name end end prompt> gem install autotest To test this example user_test.rb require File.dirname(__File__) + ‘/../test_helper’ class UserTest < Test::Unit::TestCase fixtures:users def test_full_name_without_middle_initial user = User.new(:first_name => ‘John’, :last_name => ‘Doe’)
assert_equal ‘John Doe’, user.full_name end def test_full_name_with_middle_initial user = User.new(:first_name => ‘John’, :middle_initial => ‘H’, :last_name => ‘Doe’) assert_equal ‘John H. Doe’, user.full_name end def test_full_name_with_blank_middle_initial user = User.new(:first_name => ‘John’, :middle_initial => ‘’, :last_name => ‘Doe’) assert_equal ‘John Doe’, user.full_name end end user.rb class User < ActiveRecord::Base def full_name [first_name, middle_initial,last_name].compact.join(‘ ’) end end
#to eliminate double space if middle_initial is nil so compact
class User < ActiveRecord::Base def full_name [first_name, middle_initial_with_period, last_name].compact.join(‘ ’) nil so compact end
#to eliminate double space if middle_initial is
def middle_initial_with_period “#{middle_initial}.” unless middle_initial.nil ? end def middle_initial_with_period “#{middle_initial}.” unless middle_initial.blank ? end end Example: 012_refactoring_user_name_p3 In the final part of this series you will see how to refactor your tests. Keeping tests clean is important because it will make testing easier to do in the future
Example: 034_named_routes ActionController::Routing::Routes.draw do |map| # Install the default routes as the lowest priority. map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end Recommended named routes Running http://localhost:3000/projects/ When we want to make home page this url for the site
Map.connect ‘’, :controller => ‘projects’, :action =>’index’ #This is not named route Now http://localhost:3000 is mapped with http://localhost:3000/projects/ After adding the above map Map.connect ‘home’, :controller => ‘projects’, :action =>’index’ #This is named route This will generate url_paths. <%= home_path %> # render / <%= home_url %> # render http://localhost:3000/ map.task_archieve ‘tasks/:year/:month’, :controller => ‘tasks’, :action => ‘archieve’ #year,month are placeholders can be used as <%= task_archive_path(2007,5) %> # tasks/2007/5 Alternateway: <%= task_archive_path(:year => 2007, :month=>5) %> One more example Map.resource :projects #controller = projects generates routes and bunch of routes Example: 46-catch-all-route request.request.url will output all querystring after http://localhost:3000/
# routes.rb map.connect '*path', :controller => 'redirect', :action => 'index' # redirect_controller.rb def index product = Product.find(:first, :conditions => ["name LIKE ?", "#{params[:path].first}%"]) redirect_to product_path(product)
end
Example: 013_dangers_of_model_in_session UserController.rb class UserController < ApplicationController def prepare session[:user] = User.find(:first) redirect_to :action => ‘show’ end
# prepare action to set the session
def show @user = session[:user] end def update @user = session[:user] @user.name = “foo” #these changes are temporarily and will not be stored in a database. redirect_to :action => ‘show’ end end show.rhtml <%= debug(@user) %> # for checking what is going inside the model This will output like ---ruby/object:user attributes: name : Ryan id: “1”
<% link_to ‘Update’, :action => ‘update’ %> # after clicking on this update action, username will be changed to foo user.rb class User < ActiveRecord::Base validates_presence_of :name end def update @user = session[:user] @user.name = “” @user.validate? redirect_to :action => ‘show’ end UserController.rb class UserController < ApplicationController def prepare session[:user_id] = User.find(:first).id redirect_to :action => ‘show’ end
# prepare action to set the session
def show @user = User.find(session[:user_id]) end def update @user = User.find(session[:user_id]) @user.name = “foo” #these changes are temporarily and will not be stored in a database. redirect_to :action => ‘show’
end end Above is the right way to do that Example: 014_performing_calculations_on_models prompt$ script/console Task.find(:first).priority #priority is col name Task.sum(:priority) Task.sum(:priority, :conditions => ‘completed=0’) Task.maximum(:priority) Project has many tasks p = Project.find(:first) p.tasks.sum(:priority) equivalent to Select sum(priority) as sum_priority from tasks where (tasks.project_id = 1) Example: 015_fun_with_find_conditions Tasks.count(:all,:conditions => [“complete = ? and priority =?”, false,3] Tasks.count(:all,:conditions => [“complete = ? and priority =?”, false,nil] ) # here nil = null of sql Select count(*) as count_all from tasks where (complete =0 and priority =NULL) so this is wrong Tasks.count(:all,:conditions => [“complete = ? and priority is ?”, false,nil] Tasks.count(:all,:conditions => [“complete = ? and priority IN (?)”, false, [1,3]]) Select count(*) as count_all from tasks where (complete =0 and priority IN (1,3) ) Tasks.count(:all,:conditions => [“complete = ? and priority IN (?)”, false, 0..3]) # passing ranges Select count(*) as count_all from tasks where (complete =0 and priority IN (0,1,2) )
In rails 1.2 Tasks.count(:all,:conditions => {:complete => false, :priority => 1” })
#passing hash to queries
Benefit is that we can pass other kind of object like: Tasks.count(:all,:conditions => {:complete => false, :priority => nil” }) and it will properly determines what nil is in this case. Tasks.count(:all,:conditions => {:complete => false,:priority => [1,3]”) Tasks.count(:all,:conditions => {:complete => false,:priority => 1..3”) Select count(*) as count_all from tasks where (complete =0 and `priority` between 1 and 3 ) Task.find_all_by_priority(1..3).size Example: 016_virtual_attributes REGISTER First Name Last Name Password schema.rb # This file is auto-generated from the current state of the database. Instead of editing this file, # please use the migrations feature of Active Record to incrementally modify your database, and
# then regenerate this schema definition. # # Note that this schema.rb definition is the authoritative source for your database schema. If you need # to create the application database on another system, you should be using db:schema:load, not running # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended to check this file into your version control system. ActiveRecord::Schema.define(:version => 1) do create_table "users", :force => true do |t| t.column "first_name", :password t.column "last_name", :string t.column "last_name", :string end end new.rhtml
% form_for :user :url => users_path do |f| %>
First Name <%= f.text_field :first_name %>
Last Name <%= f.text_field :last_name %>
Password <%= f.password_field :password %>
<%= submit_tag ‘Register’ %>
<% end %> Using virtual field for the above form :
% form_for :user :url => users_path do |f| %>
Full Name <%= f.text_field :full_name %>
Password <%= f.password_field :password %>
<%= submit_tag ‘Register’ %>
<% end %> user.rb
class User < ActiveRecord::Base def full_name [first_name, last_name].join(‘ ‘) end def full_name=(name) split = name.split(‘ ’,2) self.first_name = split.first self.last_name = split. last end end Example: 017_habtm_checkboxes category.rb class Category < ActiceRecord :: Base has_and_belongs_to_many :products end products.rb class Product < ActiceRecord :: Base has_and_belongs_to_many :categories end _form.rhtml <%= error_messages_for ‘product’>
Name
<%= text_field :product, :name %>
Price
<%= text_field :product, :price%>
<% for category in Category.find(:all) %>
% end %>
product_controller.rb #-------------------def create @product = Product.new(params[:product]) if @product.save flash[:notice] = “Product was successfully added” redirect_to :action => ‘index’ else render :action => ‘new’ end
end #-------------------def edit @product = Product.find(params[:id]) end #-------------------def update @product = Product.find(params[:id]) if @product.update_attributes(params[:product]) flash[:notice] = “Product was successfully updated” redirect_to :action => ‘show’, :id => @product else render :action => ‘edit’ end end #-------------------def destroy Product.find(params[:id]).destroy redirect_to :action => ‘index’ end Console One more table is there i.e categories_products p = Product.find(:first) p.category_ids = [2,3] # category_ids method is provided by has_and_belongs_to_many :categories #--------------------
def update params[:product][:category_ids] ||= [] #set to an empty array if not set any checkbox, this returns nil @product = Product.find(params[:id]) if @product.update_attributes(params[:product]) flash[:notice] = “Product was successfully updated” redirect_to :action => ‘show’, :id => @product else render :action => ‘edit’ end end Example: 018_looping_through_flash <% unless flash[:notice].nil? %>
% end %> <% unless flash[:error].nil? %>
% end %> Alternate way <% flash.each do |key, msg| %> <%= content_tag :div, msg, :id => key %> # content tag for creating the div tag <% end %> Example: 019_where_administration_goes EpisodeController.rb class EpisodesController < ApplicationController
def index @episodes = Episodes.find(:all, :order => ‘position DESC’) end def prepare session[:user_id] = User.find(:first).id redirect_to :action => ‘show’ end
# prepare action to set the session
def show @user = User.find(session[:user_id]) end def update @user = User.find(session[:user_id]) @user.name = “foo” #these changes are temporarily and will not be stored in a database. redirect_to :action => ‘show’ end end console script/generate scaffold episode ‘admin/episodes’ # for admin section http://localhost:3000/admin/episodes/list index.rhtml
% if admin? %>
% end %> application.rb class ApplicationController < ActionController::Base session :session_key => ‘_railcasts_session_id’ helper_method :admin? # this makes admin method as helper method done to make which method must be available to view as well protected def authorize
unless admin? flash[:error] = “unauthorized access” redirect_to home_path false #so that no other action executed after that end end def admin? false end
#setting it to true and false we can check restricted access
end http://localhost:3000//episodes/new class EpisodesController < ApplicationController before_filter :authorize, except => index def index @episodes = Episodes.find(:all, :order => ‘position DESC’) end def new @episode = Episode.new end #-------------------def create @episode = Episode.new(params[:episode ]) if @ episode.save flash[:notice] = “Successfully created episode” redirect_to :episodes_path
else render :action => ‘new’ end end #-------------------def edit @ episode = Episode.find(params[:id]) end #-------------------def update @episode = Episode.find(params[:id]) if @ episode.update_attributes(params[:episode]) flash[:notice] = “Successfully updated episode” redirect_to : episodes_path else render :action => ‘edit’ end end #-------------------def destroy Episode.find(params[:id]).destroy flash[:notice] = “Successfully destroyed episode” redirect_to episodes_path end end Example: 021_super_simple_authentication
Ecellent plugin acts_as_authenticated Script/plugin source http://svn.techno-weenie.net/projects/plugins Script/plugin install acts_as_authenticated Script/generate authenticated user account Rake db:migrate http://localhost:3000/account/index def admin? false end
#setting it to true and false we can check restricted access
=> def admin? current_user.name == “admin” alternate current_user.admin? end class SessionController < ApplicationController def create sessioin[:password] = params[:password] flash[:notice] = “Successfully logged in” rediret_to home_path end def destroy reset_session flash[:notice] = “Successfully logged out” rediret_to login_path
end end new.rhtml
<% form_tag sessions_path do %> Password: <%= text_field_tag :password%> <% end %>
def admin? Session[:password] == ‘foobar’ end g = Greeter.new("Pat") Greeter.instance_methods => ["method", "send", "object_id", "singleton_methods", "__send__", "equal?", "taint", "frozen?", "instance_variable_get", "kind_of?", "to_a", "instance_eval", "type", "protected_methods", "extend", "eql?", "display", "instance_variable_set", "hash", "is_a?", "to_s", "class", "tainted?", "private_methods", "untaint", "say_hi", "id", "inspect", "==", "===", "clone", "public_methods", "respond_to?", "freeze", "say_bye", "__id__", "=~", "methods", "nil?", "dup", "instance_variables", "instance_of?"] Greeter.instance_methods(false) => ["say_bye", "say_hi"]
g.respond_to?("name") => false g.respond_to?("say_hi") => true g.respond_to?("to_s") => true class Greeter attr_accessor :name end g = Greeter.new("Andy") g.respond_to?("name") => true g.respond_to?("name=") => true g.say_hi Hi Andy!
g.name="Betty" Using attr_accessor defined two new methods for us, name to get the value, and name= to set it.
Example: 034_named_routes ActionController::Routing::Routes.draw do |map| # Install the default routes as the lowest priority. map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
ri20min.rb
class MegaGreeter attr_accessor :names # Create the object def initialize(names = "World") @names = names end # Say hi to everybody def say_hi if @names.nil? puts "..." elsif @names.respond_to?("each") # @names is a list of some kind, iterate! @names.each do |name| puts "Hello #{name}!" end else puts "Hello #{@names}!" end end # Say bye to everybody def say_bye if @names.nil? puts "..." elsif @names.respond_to?("join") # Join the list elements with commas puts "Goodbye #{@names.join(", ")}. Come back soon!" else puts "Goodbye #{@names}. Come back soon!" end end
end if __FILE__ == $0 #__FILE__ is the magic variable that contains the name of the current file. $0 is the name of the file used to start the program. mg = MegaGreeter.new mg.say_hi mg.say_bye # Change name to be "Zeke" mg.names = "Zeke" mg.say_hi mg.say_bye # Change the name to an array of names mg.names = ["Albert", "Brenda", "Charles", "Dave", "Englebert"] mg.say_hi mg.say_bye # Change to nil mg.names = nil mg.say_hi mg.say_bye end Hello World! Goodbye World. Come back soon! Hello Zeke! Goodbye Zeke. Come back soon! Hello Albert! Hello Brenda! Hello Charles! Hello Dave! Hello Englebert!
Goodbye Albert, Brenda, Charles, Dave, Englebert. back soon! ... ...
people = Hash.new people[:nickname] = 'IndianGuru' people[:language] = 'Marathi' people[:lastname] = 'Talim' puts people[:lastname]
A block is like an anonymous function or lambda. a = <<END_STR This is the string And a second line END_STR # << appending to a string a = 'hello ' a<<'world.I love this world...' puts a
def self.up
Come
create_table :changesets_issues, :id => false do |t| t.column :changeset_id, :integer, :null => false t.column :issue_id, :integer, :null => false end add_index :changesets_issues, [:changeset_id, :issue_id], :unique => true, :name => :changesets_issues_ids end
Ruby Idioms def my_method(my_var) if my_var return my_var.size else return nil end end p my_method([something]) # 1 p my_method(nil) # nil def my_method(my_var) return my_var && my_var.size #if left operand is true; it return value of right operand [otherwise value of left operand] end def my_method(my_var) return my_var ? my_var.size : 0 #output 1 and 0 for above case end
def my_method(my_var) return my_var ? my_var.size : nil #output 1 and nil for above case end
Ruby Idioms [part II] def my_method Fruits = [“apple”,”banana”] Fruits += [“apple”] unless fruits.include?(“apple”) p Fruits end p my_method # will print [“apple”,”banana”] def my_method Fruits = [“apple”,”banana”] Fruits += [“orange”] unless fruits.include?(“orange”) p Fruits end p my_method # will print [“apple”,”banana”,”orange”] def my_method Fruits = [“apple”,”banana”] Fruits |= [“orange”] p Fruits end p my_method # will print [“apple”,”banana”,”orange”]
Ruby Idioms [part III] def my_method(my_var) if my_var return my_var else return no end end p my_method(“something”) # “something” p my_method(nil) # “no” def my_method(my_var) return my_var || no #if left operand is true it is returned else right operand is returned end def my_method(my_var) my_var = my_var || no return my_var end def my_method(my_var) my_var ||= no return my_var end def my_method(my_var)
my_var = “no” unless myvar return my_var end
Ruby Idioms [part VI] def my_method Fruits = [“apple”,”banana”] A = Fruits[0] B = Fruits[1] End def my_method Fruits = [“apple”,”banana”] a, b = *Fruits end def my_method *Fruits = “apple”,”banana” A = Fruits[0] B = Fruits[1] End def my_method Fruits = [“apple”,”banana”] a, b, c = *Fruits, ‘mango’ #wrong a, b, c = ‘mango’, *Fruits #right way end
def my_method fruits = [“apple”,”banana”] fn = [“Peanuts”, “cashew”, fruits] p fn end def my_method fruits = [“apple”,”banana”] fn = [“Peanuts”, “cashew”, fruits] fruits[0] = “mango” #this will not change actual contents for fruits and nuts but It will create copy p fn end def my_method fruits = [“apple”,”banana”] fn = [“Peanuts”, “cashew”, *fruits] fruits[0] = “mango” #this is case of reference so it will change actual value p fn end def my_favourites(*fruits) fruits = end my_favourites (:mango, :orange, :banana) #[:mango, :orange, :banana] p my_favourites
Ruby Idioms [part V]
val = [1,2,3] a, b, c = val #parallel assignement pa#1 pb#2 pc#3 def test [10, “tintin”] end val, str = test p val # 10 p str # “tintin” “bugs funny bunny” =~ /bugs(.+) bunny/ # . means any character except ‘\n’ + 1 or more +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
observe_field - Passing Parameters Home Page | All Pages | Recently Revised | Feed
Passing the default parameter <%= observe_field 'search', :frequency => 0.5, :update => 'target_id', :url =>
{ :controller => '
Passing multiple parameters <select name="section" id="section"> <%= observe_field "search", :url => {:controller => "search", :action => "list"}, :with => "'section='+ escape($('section').value) + '&search=' + escape(value)", :update => "search_results" %>
To answer an earlier question here: Each parameter passed in should be escaped. Otherwise, the right sequence of characters can create additional parameters. While probably not a security risk, it’s good practice and guarantees the users’ input will be passed in full.
Another Way I couldn’t get the above example to work…perhaps due to the fact that I was using the Rails Form Helpers and not the HTML Form tags. A little research into the prototype.js documentation I found at Particletree helped me come up with the following: <%= observe_field("field1", :frequency => 1, :update => "span1", :url => {:action => :calculate_total}, :with => "'values='+escape(value) + ' ' + $F('field2')") %>
I used the $F function from the prototype library to add the value of the additional field. In my controller, the ‘values’ string from the :with argument is passed into params[:values]. I can then use string manipulators (which is why I added the space between the two field values) to access the values I need to perform the server side operations and then render them in the partial(s) I choose. Like so:
def calculate_total a = params[:values] i = a.split[0].to_i i2 = a.split[1].to_f i2 = i2/100 cv = i - (i*i2) render :text => cv.to_s end
Hope this helps someone…
Yet Another Way Here is another way to pass multiple parameters documented here. Using Prototype Form.serializeElements() function, you can achieve the same thing, and it has the advantages of preserving the params key assigned to the html elements if they are created using form_for or fields_for. observe_field :target_dom_id, :url => some_named_route_url, :method => :get, :with => "Form.serializeElements($('text_field_one', 'text_field_two', ...))"
Default method Don’t forget that simply doing this: <%= observe_field("field1", :frequency => 1, :update => "span1", :url => {:action => :calculate_total}, :with => "stuff") %>
will put the current value of ‘field1’ into params[:stuff] accessible to your RJS templates. But, be warned that if the field contains an ampersand (&), more than one params element may be passed. For example, if in field1 an end user typed in “hello&hi=greetings”, then params[:stuff]"hello" params[:hi]“greetings”
This is usually not the desired behavior, so you’ll probably want to use :with => “‘stuff=’+escape(value)”
which, in this example, will result in params[:stuff]==“hello&hi=greetings”
Escaping ≠ no problems While i solved the &-problem using :with => "'value='+escape(value)"
it still fails to submit ‘+’-signs. First i considered a client and server solution (replacing on client and back-replacing on server) but after reading that the escape-method is deprecated i tried the alternatives and this works well for me: :with => "'value='+encodeURIComponent(value)"
Identical Format to a Form Submit If you’re using something like <%= password_field "user", "password", :size => 20, :value=>"" %>
to create your form and would like to have a partial ajax submit through an observe_field call to have the same format as the final full form submit then use this format. ie. here combined password and password confirmation. <%= observe_field "user_password_confirmation", ... :with => "'user[password_confirmation]=' + encodeURIComponent(value) + '&user[password]=' + encodeURIComponent($('user_password').value)" %>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ require 'date' y2k = Time.gm(2000, 1, 1) y2k + 1 y2k - 1 y2k + (60 * 60 * 24 * 365)
# # # #
=> => => =>
Sat Sat Fri Sun
y2k_dt = DateTime.new(2000, 1, 1) (y2k_dt + 1).to_s (y2k_dt - 1).to_s (y2k_dt + 0.5).to_s (y2k_dt + 365).to_s
# # # #
=> => => =>
"2000-01-02T00:00:00Z" "1999-12-31T00:00:00Z" "2000-01-01T12:00:00Z" "2000-12-31T00:00:00Z"
Jan Jan Dec Dec
01 01 31 31
00:00:00 00:00:01 23:59:59 00:00:00
UTC UTC UTC UTC
2000 2000 1999 2000
Subtracting one Time from another gives the interval between the dates, in seconds. Subtracting one Date from another gives the interval in days: day_one day_two day_two day_one
= = -
Time.gm(1999, 12, 31) Time.gm(2000, 1, 1) day_one day_two
day_one = DateTime.new(1999, 12, 31)
# => 86400.0 # => -86400.0
day_two = DateTime.new(2000, 1, 1) day_two - day_one day_one - day_two
# => Rational(1, 1) # => Rational(-1, 1)
# Compare times from now and 10 seconds in the future. before_time = Time.now before_datetime = DateTime.now sleep(10) Time.now - before_time # => 10.003414 DateTime.now - before_datetime # => Rational(5001557, 43200000000)
The activesupport gem, a prerequisite of Ruby on Rails, defines many useful functions on Numeric and Time for navigating through time:[2] [2]
So does the Facets More library. require 'rubygems' require 'active_support' 10.days.ago 1.month.from_now 2.weeks.since(Time.local(2006, 1, 1))
# => Wed Mar 08 19:54:17 EST 2006 # => Mon Apr 17 20:54:17 EDT 2006 # => Sun Jan 15 00:00:00 EST 2006
y2k - 1.day y2k + 6.3.years 6.3.years.since y2k
# => Fri Dec 31 00:00:00 UTC 1999 # => Thu Apr 20 01:48:00 UTC 2006 # => Thu Apr 20 01:48:00 UTC 2006
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Related Documents