diff options
34 files changed, 547 insertions, 170 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 1bde73563e..1e91d62e24 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -297,6 +297,10 @@ module ActionMailer #:nodoc: # information and a cryptographic Message Digest 5 algorithm to hash important information) # * <tt>:enable_starttls_auto</tt> - When set to true, detects if STARTTLS is enabled in your SMTP server # and starts to use it. + # * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is + # really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name + # of an OpenSSL verify constant ('none', 'peer', 'client_once','fail_if_no_peer_cert') or directly the + # constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER,...). # # * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method. # * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>. @@ -682,6 +686,9 @@ module ActionMailer #:nodoc: end end + # Translates the +subject+ using Rails I18n class under <tt>[:actionmailer, mailer_scope, action_name]</tt> scope. + # If it does not find a translation for the +subject+ under the specified scope it will default to a + # humanized version of the <tt>action_name</tt>. def default_i18n_subject #:nodoc: mailer_scope = self.class.mailer_name.gsub('/', '.') I18n.t(:subject, :scope => [mailer_scope, action_name], :default => action_name.humanize) diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 313a2591bf..9277359d5c 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -51,7 +51,7 @@ module ActionView # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years - # distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days + # distance_of_time_in_words(from_time, from_time + 60.hours) # => 3 days # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute @@ -112,10 +112,12 @@ module ActionView # # ==== Examples # time_ago_in_words(3.minutes.from_now) # => 3 minutes - # time_ago_in_words(Time.now - 15.hours) # => 15 hours + # time_ago_in_words(Time.now - 15.hours) # => about 15 hours # time_ago_in_words(Time.now) # => less than a minute # - # from_time = Time.now - 3.days - 14.minutes - 25.seconds # => 3 days + # from_time = Time.now - 3.days - 14.minutes - 25.seconds + # time_ago_in_words(from_time) # => 3 days + # def time_ago_in_words(from_time, include_seconds = false) distance_of_time_in_words(from_time, Time.now, include_seconds) end @@ -464,7 +466,7 @@ module ActionView # # # Generates a select field for hours with a custom prompt. Use :prompt => true for a # # generic prompt. - # select_hour(13, :prompt =>'Choose hour') + # select_hour(13, :prompt => 'Choose hour') # def select_hour(datetime, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_hour diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 05a9c5b4f1..b545031fcc 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -100,7 +100,7 @@ module ActionView # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506 # number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,506 € # - # number_to_currency(1234567890.50, :negative_format => "(%u%n)") + # number_to_currency(-1234567890.50, :negative_format => "(%u%n)") # # => ($1,234,567,890.51) # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "") # # => £1234567890,50 @@ -238,7 +238,7 @@ module ActionView # number_with_precision(111.2345, :precision => 1, :significant => true) # => 100 # number_with_precision(13, :precision => 5, :significant => true) # => 13.000 # number_with_precision(111.234, :locale => :fr) # => 111,234 - # number_with_precision(13, :precision => 5, :significant => true, strip_insignificant_zeros => true) + # number_with_precision(13, :precision => 5, :significant => true, :strip_insignificant_zeros => true) # # => 13 # number_with_precision(389.32314, :precision => 4, :significant => true) # => 389.3 # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.') @@ -318,7 +318,7 @@ module ActionView # Non-significant zeros after the fractional separator are stripped out by default (set # <tt>:strip_insignificant_zeros</tt> to +false+ to change that): # number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB" - # number_to_human_size(524288000, :precision=>5) # => "500 MB" + # number_to_human_size(524288000, :precision => 5) # => "500 MB" def number_to_human_size(number, options = {}) options.symbolize_keys! @@ -407,7 +407,7 @@ module ActionView # Unsignificant zeros after the decimal separator are stripped out by default (set # <tt>:strip_insignificant_zeros</tt> to +false+ to change that): # number_to_human(12345012345, :significant_digits => 6) # => "12.345 Billion" - # number_to_human(500000000, :precision=>5) # => "500 Million" + # number_to_human(500000000, :precision => 5) # => "500 Million" # # ==== Custom Unit Quantifiers # diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 0fee34f8a4..841be0a567 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -94,7 +94,7 @@ module ActionView # # => Please e-mail me at me@email.com. # # strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.') - # # => Blog: Visit + # # => Blog: Visit. def strip_links(html) self.class.link_sanitizer.sanitize(html) end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index bdda1df437..06e2b027da 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -19,7 +19,7 @@ module ActionView # simple_format('<a href="http://example.com/">Example</a>') # # => "<p><a href=\"http://example.com/\">Example</a></p>" # - # simple_format('<a href="javascript:alert('no!')">Example</a>') + # simple_format('<a href="javascript:alert(\'no!\')">Example</a>') # # => "<p><a>Example</a></p>" # # If you want to escape all content, you should invoke the +h+ method before @@ -295,11 +295,11 @@ module ActionView # +link+ as its optional second parameter and the +html_options+ hash # as its optional third parameter: # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." - # auto_link(post_body, :urls) # => Once upon\na time + # auto_link(post_body, :urls) # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>. # Please e-mail me at me@email.com." # - # auto_link(post_body, :all, :target => "_blank") # => Once upon\na time + # auto_link(post_body, :all, :target => "_blank") # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>. # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>." def auto_link(text, *args, &block)#link = :all, html = {}, &block) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index de75488e72..051d3eb049 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -555,10 +555,10 @@ module ActionView # current_page?(:controller => 'shop', :action => 'checkout') # # => true # - # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'1') + # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '1') # # => true # - # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'2') + # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '2') # # => false # # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc') diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb index ab1fa7cd5b..9eba4642b8 100644 --- a/activesupport/lib/active_support/core_ext/array/random_access.rb +++ b/activesupport/lib/active_support/core_ext/array/random_access.rb @@ -1,12 +1,15 @@ class Array # Backport of Array#sample based on Marc-Andre Lafortune's https://github.com/marcandre/backports/ # Returns a random element or +n+ random elements from the array. - # If the array is empty and +n+ is nil, returns <tt>nil</tt>. if +n+ is passed, returns <tt>[]</tt>. + # If the array is empty and +n+ is nil, returns <tt>nil</tt>. + # If +n+ is passed and its value is less than 0, it raises an +ArgumentError+ exception. + # If the value of +n+ is equal or greater than 0 it returns <tt>[]</tt>. # - # [1,2,3,4,5,6].sample # => 4 - # [1,2,3,4,5,6].sample(3) # => [2, 4, 5] - # [].sample # => nil - # [].sample(3) # => [] + # [1,2,3,4,5,6].sample # => 4 + # [1,2,3,4,5,6].sample(3) # => [2, 4, 5] + # [1,2,3,4,5,6].sample(-3) # => ArgumentError: negative sample number + # [].sample # => nil + # [].sample(3) # => [] def sample(n=nil) return self[Kernel.rand(size)] if n.nil? n = n.to_int diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index d0c1ea8326..20085c4fb3 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -18,8 +18,8 @@ class Object !blank? end - # Returns object if it's #present? otherwise returns nil. - # object.presence is equivalent to object.present? ? object : nil. + # Returns object if it's <tt>present?</tt> otherwise returns +nil+. + # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>. # # This is handy for any representation of objects where blank is the same # as not present at all. For example, this simplifies a common check for @@ -37,39 +37,72 @@ class Object end end -class NilClass #:nodoc: +class NilClass + # +nil+ is blank: + # + # nil.blank? # => true + # def blank? true end end -class FalseClass #:nodoc: +class FalseClass + # +false+ is blank: + # + # false.blank? # => true + # def blank? true end end -class TrueClass #:nodoc: +class TrueClass + # +true+ is not blank: + # + # true.blank? # => false + # def blank? false end end -class Array #:nodoc: +class Array + # An array is blank if it's empty: + # + # [].blank? # => true + # [1,2,3].blank? # => false + # alias_method :blank?, :empty? end -class Hash #:nodoc: +class Hash + # A hash is blank if it's empty: + # + # {}.blank? # => true + # {:key => 'value'}.blank? # => false + # alias_method :blank?, :empty? end -class String #:nodoc: +class String + # A string is blank if it's empty or contains whitespaces only: + # + # "".blank? # => true + # " ".blank? # => true + # " something here ".blank? # => false + # def blank? self !~ /\S/ end end class Numeric #:nodoc: + # No number is blank: + # + # 1.blank? # => false + # 0.blank? # => false + # def blank? false end diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index b05325790c..02cb5dfee7 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -15,50 +15,89 @@ # That's why we hardcode the following cases and check duplicable? instead of # using that rescue idiom. class Object - # Can you safely .dup this object? - # False for nil, false, true, symbols, numbers, class and module objects; true otherwise. + # Can you safely dup this object? + # + # False for +nil+, +false+, +true+, symbols, numbers, class and module objects; + # true otherwise. def duplicable? true end end -class NilClass #:nodoc: +class NilClass + # +nil+ is not duplicable: + # + # nil.duplicable? # => false + # nil.dup # => TypeError: can't dup NilClass + # def duplicable? false end end -class FalseClass #:nodoc: +class FalseClass + # +false+ is not duplicable: + # + # false.duplicable? # => false + # false.dup # => TypeError: can't dup FalseClass + # def duplicable? false end end -class TrueClass #:nodoc: +class TrueClass + # +true+ is not duplicable: + # + # true.duplicable? # => false + # true.dup # => TypeError: can't dup TrueClass + # def duplicable? false end end -class Symbol #:nodoc: +class Symbol + # Symbols are not duplicable: + # + # :my_symbol.duplicable? # => false + # :my_symbol.dup # => TypeError: can't dup Symbol + # def duplicable? false end end -class Numeric #:nodoc: +class Numeric + # Numbers are not duplicable: + # + # 3.duplicable? # => false + # 3.dup # => TypeError: can't dup Fixnum + # def duplicable? false end end -class Class #:nodoc: +class Class + # Classes are not duplicable: + # + # c = Class.new # => #<Class:0x10328fd80> + # c.dup # => #<Class:0x10328fd80> + # + # Note +dup+ returned the same class object. def duplicable? false end end -class Module #:nodoc: +class Module + # Modules are not duplicable: + # + # m = Module.new # => #<Module:0x10328b6e0> + # m.dup # => #<Module:0x10328b6e0> + # + # Note +dup+ returned the same module object. def duplicable? false end diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 04619124a1..aedf5c8c82 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -9,12 +9,12 @@ class Object # # ==== Examples # - # Without try + # Without +try+ # @person && @person.name # or # @person ? @person.name : nil # - # With try + # With +try+ # @person.try(:name) # # +try+ also accepts arguments and/or a block, for the method it is trying @@ -34,7 +34,19 @@ class Object end end -class NilClass #:nodoc: +class NilClass + # Instances of +NilClass+ return always +nil+. + # It becomes specially helpful when navigating through associations that may return +nil+. + # + # === Examples + # + # nil.try(:name) # => nil + # + # Without +try+ + # @person && !@person.children.blank? && @person.children.first.name + # + # With +try+ + # @person.try(:children).try(:first).try(:name) def try(*args) nil end diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index 496dc7224b..f8b586c151 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -368,7 +368,7 @@ class UsersController < ApplicationController respond_to do |format| format.html # index.html.erb format.xml { render :xml => @users} - format.json { render :json => @users} + format.json { render :json => @users} end end end diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index d0b3ee6bfc..172932fdab 100644 --- a/railties/guides/source/action_view_overview.textile +++ b/railties/guides/source/action_view_overview.textile @@ -20,7 +20,28 @@ Note: Some features of Action View are tied to Active Record, but that doesn't m h3. Using Action View with Rails -TODO... +For each controller there is an associated directory in the <tt>app/views</tt> directory which holds the template files that make up the views associated with that controller. These files are used to display the view that results from each controller action. + +Let's take a look at what Rails does by default when creating a new resource using the scaffold generator: + +<shell> +$ rails generate scaffold post + [...] + invoke scaffold_controller + create app/controllers/posts_controller.rb + invoke erb + create app/views/posts + create app/views/posts/index.html.erb + create app/views/posts/edit.html.erb + create app/views/posts/show.html.erb + create app/views/posts/new.html.erb + create app/views/posts/_form.html.erb + [...] +</shell> + +There is a naming convention for views in Rails. Typically, the views share their name with the associated controller action, as you can see above. +For example, the index controller action of the <tt>posts_controller.rb</tt> will use the <tt>index.html.erb</tt> view file in the <tt>app/views/posts</tt> directory. +The complete HTML returned to the client is composed of a combination of this ERB file, a layout template that wraps it, and all the partials that the view may reference. Later on this guide you can find a more detailed documentation of each one of this three components. h3. Using Action View outside of Rails @@ -94,9 +115,213 @@ TODO needs a screenshot? I have one - not sure where to put it. h3. Templates, Partials and Layouts -TODO... +As mentioned before, the final HTML output is a composition of three Rails elements: +Templates+, +Partials+ and +Layouts+. +Find below a brief overview of each one of them. + +h4. Templates + +Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERB (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> extension then a fresh instance of <tt>Builder::XmlMarkup</tt> library is used. + +Rails supports multiple template systems and uses a file extension to distinguish amongst them. For example, an HTML file using the ERB template system will have <tt>.html.erb</tt> as a file extension. + +h5. ERB + +Within an ERB template Ruby code can be included using both +<% %>+ and +<%= %>+ tags. The +<% %>+ are used to execute Ruby code that does not return anything, such as conditions, loops or blocks, and the +<%= %>+ tags are used when you want output. + +Consider the following loop for names: + +<erb> +<b>Names of all the people</b> +<% @people.each do |person| %> + Name: <%= person.name %><br/> +<% end %> +</erb> + +The loop is setup in regular embedding tags +<% %>+ and the name is written using the output embedding tag +<%= %>+. Note that this is not just a usage suggestion, for Regular output functions like print or puts won't work with ERB templates. So this would be wrong: + +<erb> +<%# WRONG %> +Hi, Mr. <% puts "Frodo" %> +</erb> + +To suppress leading and trailing whitespaces, you can use +<%-+ +-%>+ interchangeably with +<%+ and +%>+. + +h5. Builder + +Builder templates are a more programmatic alternative to ERB. They are especially useful for generating XML content. An XmlMarkup object named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension. + +Here are some basic examples: + +<ruby> +xml.em("emphasized") +xml.em { xml.b("emph & bold") } +xml.a("A Link", "href"=>"http://rubyonrails.org") +xml.target("name"=>"compile", "option"=>"fast") +</ruby> + +will produce + +<html> +<em>emphasized</em> +<em><b>emph & bold</b></em> +<a href="http://rubyonrails.org">A link</a> +<target option="fast" name="compile" \> +</html> + +Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following: + +<ruby> +xml.div { + xml.h1(@person.name) + xml.p(@person.bio) +} +</ruby> + +would produce something like: + +<html> +<div> + <h1>David Heinemeier Hansson</h1> + <p>A product of Danish Design during the Winter of '79...</p> +</div> +</html> + +A full-length RSS example actually used on Basecamp: + +<ruby> +xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do + xml.channel do + xml.title(@feed_title) + xml.link(@url) + xml.description "Basecamp: Recent items" + xml.language "en-us" + xml.ttl "40" + + for item in @recent_items + xml.item do + xml.title(item_title(item)) + xml.description(item_description(item)) if item_description(item) + xml.pubDate(item_pubDate(item)) + xml.guid(@person.firm.account.url + @recent_items.url(item)) + xml.link(@person.firm.account.url + @recent_items.url(item)) + xml.tag!("dc:creator", item.author_name) if item_has_creator?(item) + end + end + end +end +</ruby> + +h5. Template caching + +By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will check the file's modification time and recompile it in development mode. + +h4. Partials -TODO see http://guides.rubyonrails.org/layouts_and_rendering.html +Partial templates – usually just called "partials" – are another device for breaking the rendering process into more manageable chunks. With a partial, you can move the code for rendering a particular piece of a response to its own file. + +h5. Naming Partials + +To render a partial as part of a view, you use the +render+ method within the view: + +<ruby> +<%= render "menu" %> +</ruby> + +This will render a file named +_menu.html.erb+ at that point within the view is being rendered. Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore. This holds true even when you're pulling in a partial from another folder: + +<ruby> +<%= render "shared/menu" %> +</ruby> + +That code will pull in the partial from +app/views/shared/_menu.html.erb+. + +h5. Using Partials to Simplify Views + +One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that you can grasp what's going on more easily. For example, you might have a view that looked like this: + +<erb> +<%= render "shared/ad_banner" %> + +<h1>Products</h1> + +<p>Here are a few of our fine products:</p> +<% @products.each do |product| %> + <%= render :partial => "product", :locals => { :product => product } %> +<% end %> + +<%= render "shared/footer" %> +</erb> + +Here, the +_ad_banner.html.erb+ and +_footer.html.erb+ partials could contain content that is shared among many pages in your application. You don't need to see the details of these sections when you're concentrating on a particular page. + +h5. The :as and :object options + +By default <tt>ActionView::Partials::PartialRenderer</tt> has its object in a local variable with the same name as the template. So, given + +<erb> +<%= render :partial => "product" %> +</erb> + +within product we'll get <tt>@product</tt> in the local variable +product+, as if we had written: + +<erb> +<%= render :partial => "product", :locals => { :product => @product } %> +</erb> + +With the <tt>:as</tt> option we can specify a different name for said local variable. For example, if we wanted it to be +item+ instead of product+ we'd do: + +<erb> +<%= render :partial => "product", :as => 'item' %> +</erb> + +The <tt>:object</tt> option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere, in a different ivar or in a local variable for instance. + +For example, instead of: + +<erb> +<%= render :partial => "product", :locals => { :product => @item } %> +</erb> + +you'd do: + +<erb> +<%= render :partial => "product", :object => @item %> +</erb> + +The <tt>:object</tt> and <tt>:as</tt> options can be used together. + +h5. Rendering Collections + +The example of partial use describes a familiar pattern where a template needs to iterate over an array and render a sub template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders a partial by the same name as the elements contained within. +So the three-lined example for rendering all the products can be rewritten with a single line: + +<erb> +<%= render :partial => "product", :collection => @products %> +</erb> + +When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+ , and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered. + +You can use a shorthand syntax for rendering collections. Assuming @products is a collection of +Product+ instances, you can simply write the following to produce the same result: + +<erb> +<%= render @products %> +</erb> + +Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection. + +h5. Spacer Templates + +You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option: + +<erb> +<%= render @products, :spacer_template => "product_ruler" %> +</erb> + +Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials. + +h4. Layouts + +TODO... h3. Using Templates, Partials and Layouts in "The Rails Way" @@ -262,9 +487,9 @@ Register one or more stylesheet files to be included when symbol is passed to +s ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] stylesheet_link_tag :monkey # => - <link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" /> - <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" /> - <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" /> </ruby> h5. auto_discovery_link_tag @@ -1472,5 +1697,6 @@ You can read more about the Rails Internationalization (I18n) API "here":i18n.ht h3. Changelog +* April 16, 2011: Added 'Using Action View with Rails', 'Templates' and 'Partials' sections. "Sebastian Martinez":http://wyeworks.com * September 3, 2009: Continuing work by Trevor Turk, leveraging the Action Pack docs and "What's new in Edge Rails":http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts * April 5, 2009: Starting work by Trevor Turk, leveraging Mike Gunderloy's docs diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index df8e35ed33..7cdffe4c2e 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -546,7 +546,7 @@ Active Record provides two locking mechanisms: h4. Optimistic Locking -Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of conflicts with the data. It does this by checking whether another process has made changes to a record since it was opened. An +ActiveRecord::StaleObjectError+ exception is thrown if that has occurred and the update is ignored. +Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of conflicts with the data. It does this by checking whether another process has made changes to a record since it was opened. An +ActiveRecord::StaleObjectError+ exception is thrown if that has occurred and the update is ignored. <strong>Optimistic locking column</strong> @@ -993,7 +993,7 @@ Client.count # SELECT count(*) AS count_all FROM clients </ruby> -Or on a relation : +Or on a relation: <ruby> Client.where(:first_name => 'Ryan').count @@ -1060,7 +1060,7 @@ If you want to find the sum of a field for all records in your table you can cal Client.sum("orders_count") </ruby> -For options, please see the parent section, "Calculations":#calculations. +For options, please see the parent section, "Calculations":#calculations. h3. Changelog diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index c65dd52e48..9aab4b6694 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -552,6 +552,21 @@ class Account < ActiveRecord::Base end </ruby> +h4. Grouping conditional validations + +Sometimes it is useful to have multiple validations use one condition, it can be easily achieved using +with_options+. + +<ruby> +class User < ActiveRecord::Base + with_options :if => :is_admin? do |admin| + admin.validates_length_of :password, :minimum => 10 + admin.validates_presence_of :email + end +end +</ruby> + +All validations inside of +with_options+ block will have automatically passed the condition +:if => :is_admin?+ + h3. Creating Custom Validation Methods When the built-in validation helpers are not enough for your needs, you can write your own validation methods. diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 3ba840c044..b7f842a0d0 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -442,9 +442,9 @@ require_library_or_gem('mysql') NOTE: Defined in +active_support/core_ext/kernel/requires.rb+. -h4. +in?+ and +either?+ +h4. +in?+ -The predicate +in?+ tests if an object is included in another object, and the predicate +either?+ tests if an object is included in a list of objects which will be passed as arguments. +The predicate +in?+ tests if an object is included in another object. An +ArgumentError+ exception will be raised if the argument passed does not respond to +include?+. Examples of +in?+: @@ -454,14 +454,6 @@ Examples of +in?+: 25.in?(30..50) # => false </ruby> -Examples of +either?+: - -<ruby> - 1.either?(1,2,3) # => true - 5.either?(1,2,3) # => false - [1,2,3].either?([1,2,3], 2, [3,4,5]) # => true -</ruby> - NOTE: Defined in +active_support/core_ext/object/inclusion.rb+. h3. Extensions to +Module+ diff --git a/railties/guides/source/ajax_on_rails.textile b/railties/guides/source/ajax_on_rails.textile index 38a63ea483..1566c23414 100644 --- a/railties/guides/source/ajax_on_rails.textile +++ b/railties/guides/source/ajax_on_rails.textile @@ -42,7 +42,7 @@ You are ready to add some AJAX love to your Rails app! h4. The Quintessential AJAX Rails Helper: link_to_remote -Let's start with what is probably the most often used helper: +link_to_remote+. It has an interesting feature from the documentation point of view: the options supplied to +link_to_remote+ are shared by all other AJAX helpers, so learning the mechanics and options of +link_to_remote+ is a great help when using other helpers. +Let's start with what is probably the most often used helper: +link_to_remote+. It has an interesting feature from the documentation point of view: the options supplied to +link_to_remote+ are shared by all other AJAX helpers, so learning the mechanics and options of +link_to_remote+ is a great help when using other helpers. The signature of +link_to_remote+ function is the same as that of the standard +link_to+ helper: @@ -72,7 +72,7 @@ link_to_remote "Add to cart", If the server returns 200, the output of the above example is equivalent to our first, simple one. However, in case of error, the element with the DOM id +error+ is updated rather than the +cart+ element. -** *position* By default (i.e. when not specifying this option, like in the examples before) the repsonse is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the +position+ parameter, with four possibilities: +** *position* By default (i.e. when not specifying this option, like in the examples before) the repsonse is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the +position+ parameter, with four possibilities: *** +:before+ Inserts the response text just before the target element. More precisely, it creates a text node from the response and inserts it as the left sibling of the target element. *** +:after+ Similar behavior to +:before+, but in this case the response is inserted after the target element. *** +:top+ Inserts the text into the target element, before it's original content. If the target element was empty, this is equivalent with not specifying +:position+ at all. diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 297ba2d661..799339e674 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -25,7 +25,7 @@ h4. Page Caching Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the webserver (i.e. apache or nginx), without ever having to go through the Rails stack at all. Obviously, this is super-fast. Unfortunately, it can't be applied to every situation (such as pages that need authentication) and since the webserver is literally just serving a file from the filesystem, cache expiration is an issue that needs to be dealt with. -So, how do you enable this super-fast cache behavior? Simple, let's say you have a controller called +ProductsController+ and an +index+ action that lists all the products +So, how do you enable this super-fast cache behavior? Simple, let's say you have a controller called +ProductsController+ and an +index+ action that lists all the products <ruby> class ProductsController < ActionController @@ -152,7 +152,7 @@ expire_fragment('all_available_products') h4. Sweepers -Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter. +Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter. Continuing with our Product controller example, we could rewrite it with a sweeper like this: @@ -230,9 +230,9 @@ class ProductsController < ActionController end </ruby> -The second time the same query is run against the database, it's not actually going to hit the database. The first time the result is returned from the query it is stored in the query cache (in memory) and the second time it's pulled from memory. +The second time the same query is run against the database, it's not actually going to hit the database. The first time the result is returned from the query it is stored in the query cache (in memory) and the second time it's pulled from memory. -However, it's important to note that query caches are created at the start of an action and destroyed at the end of that action and thus persist only for the duration of the action. If you'd like to store query results in a more persistent fashion, you can in Rails by using low level caching. +However, it's important to note that query caches are created at the start of an action and destroyed at the end of that action and thus persist only for the duration of the action. If you'd like to store query results in a more persistent fashion, you can in Rails by using low level caching. h3. Cache Stores @@ -322,7 +322,7 @@ You can use Hashes and Arrays of values as cache keys. <ruby> # This is a legal cache key -Rails.cache.read(:site => "mysite", :owners => [owner_1, owner2]) +Rails.cache.read(:site => "mysite", :owners => [owner_1, owner_2]) </ruby> The keys you use on +Rails.cache+ will not be the same as those actually used with the storage engine. They may be modified with a namespace or altered to fit technology backend constraints. This means, for instance, that you can't save values with +Rails.cache+ and then try to pull them out with the +memcache-client+ gem. However, you also don't need to worry about exceeding the memcached size limit or violating syntax rules. @@ -352,7 +352,7 @@ class ProductsController < ApplicationController # If the request is fresh (i.e. it's not modified) then you don't need to do # anything. The default render checks for this using the parameters # used in the previous call to stale? and will automatically send a - # :not_modified. So that's it, you're done. + # :not_modified. So that's it, you're done. end </ruby> diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index 9d8a9caf08..ad36c6532e 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -8,10 +8,10 @@ Rails comes with every command line tool you'll need to * Mess with objects through an interactive shell * Profile and benchmark your new creation -NOTE: This tutorial assumes you have basic Rails knowledge from reading the "Getting Started with Rails Guide":getting_started.html. - endprologue. +NOTE: This tutorial assumes you have basic Rails knowledge from reading the "Getting Started with Rails Guide":getting_started.html. + WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails. h3. Command Line Basics @@ -144,10 +144,13 @@ $ rails generate controller Greetings hello create app/helpers/greetings_helper.rb invoke test_unit create test/unit/helpers/greetings_helper_test.rb + invoke assets + create app/assets/javascripts/greetings.js + create app/assets/stylesheets/greetings.css </shell> -What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a functional test file, a helper for the view, and a view file. +What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a javascript file and a stylesheet file. Check out the controller and modify it a little (in +app/controllers/greetings_controller.rb+): diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile index 1fcc4fd7e3..cbc4acfeca 100644 --- a/railties/guides/source/contributing_to_ruby_on_rails.textile +++ b/railties/guides/source/contributing_to_ruby_on_rails.textile @@ -314,14 +314,20 @@ You should not be the only person who looks at the code before you submit it. Yo You might also want to check out the "RailsBridge BugMash":http://wiki.railsbridge.org/projects/railsbridge/wiki/BugMash as a way to get involved in a group effort to improve Rails. This can help you get started and help check your code when you're writing your first patches. +h4. Create a Lighthouse Ticket + +Now create a ticket for your patch. Go to the "new ticket":http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/new page at Lighthouse. Fill in a reasonable title and description, as well as tag the ticket with the ‘patch’ tag and whatever other subject area tags make sense. Write down your ticket number, for you will need it in the following step. + h4. Commit Your Changes When you're happy with the code on your computer, you need to commit the changes to git: <shell> -$ git commit -a -m "Here is a commit message" +$ git commit -a -m "Here is a commit message [#ticket_number state:committed]" </shell> +NOTE: By adding '[#ticket_number state:committed]' at the end of your commit message, the ticket will automatically change its status to commited once your patch is pushed to the repository. + h4. Update master It’s pretty likely that other changes to master have happened while you were working. Go get them: @@ -361,13 +367,12 @@ $ git apply --check my_new_patch.diff Please make sure the patch does not introduce whitespace errors: <shell> -$ git apply --whitespace=error-all mynew_patch.diff +$ git apply --whitespace=error-all my_new_patch.diff </shell> +h4. Attach your Patch to the Lighthouse Ticket -h4. Create a Lighthouse Ticket - -Now create a ticket with your patch. Go to the "new ticket":http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/new page at Lighthouse. Fill in a reasonable title and description, remember to attach your patch file, and tag the ticket with the ‘patch’ tag and whatever other subject area tags make sense. +Now you need to update the ticket by attaching the patch file you just created. h4. Get Some Feedback @@ -385,6 +390,7 @@ All contributions, either via master or docrails, get credit in "Rails Contribut h3. Changelog +* April 14, 2001: Modified Contributing to the Rails Code section to add '[#ticket_number state:commited]' on patches commit messages by "Sebastian Martinez":http://wyeworks.com * December 28, 2010: Complete revision by "Xavier Noria":credits.html#fxn * April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * August 1, 2009: Updates/amplifications by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/debugging_rails_applications.textile b/railties/guides/source/debugging_rails_applications.textile index fb17dccfb8..477ff29dbd 100644 --- a/railties/guides/source/debugging_rails_applications.textile +++ b/railties/guides/source/debugging_rails_applications.textile @@ -308,6 +308,41 @@ If you repeat the +list+ command, this time using just +l+, the next ten lines o And so on until the end of the current file. When the end of file is reached, the +list+ command will start again from the beginning of the file and continue again up to the end, treating the file as a circular buffer. +On the other hand, to see the previous ten lines you should type +list-+ (or +l-+) + +<shell> +(rdb:7) l- +[1, 10] in /PathToProject/posts_controller.rb + 1 class PostsController < ApplicationController + 2 # GET /posts + 3 # GET /posts.xml + 4 def index + 5 debugger + 6 @posts = Post.all + 7 + 8 respond_to do |format| + 9 format.html # index.html.erb + 10 format.xml { render :xml => @posts } +</shell> + +This way you can move inside the file, being able to see the code above and over the line you added the +debugger+. +Finally, to see where you are in the code again you can type +list=+ + +<shell> +(rdb:7) list= +[1, 10] in /PathToProject/posts_controller.rb + 1 class PostsController < ApplicationController + 2 # GET /posts + 3 # GET /posts.xml + 4 def index + 5 debugger +=> 6 @posts = Post.all + 7 + 8 respond_to do |format| + 9 format.html # index.html.erb + 10 format.xml { render :xml => @posts } +</shell> + h4. The Context When you start debugging your application, you will be placed in different contexts as you go through the different parts of the stack. diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index 1f21c27ae6..a63245acec 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -258,7 +258,7 @@ The name passed to +form_for+ controls the key used in +params+ to access the fo The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder. -You can create a similar binding without actually creating +<form>+ tags with the +fields_for+ helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for creating both like so: +You can create a similar binding without actually creating +<form>+ tags with the +fields_for+ helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for creating both like so: <erb> <%= form_for @person, :url => { :action => "create" } do |person_form| %> @@ -438,7 +438,7 @@ As with other helpers, if you were to use the +select+ helper on a form builder <%= f.select(:city_id, ...) %> </erb> -WARNING: If you are using +select+ (or similar helpers such as +collection_select+, +select_tag+) to set a +belongs_to+ association you must pass the name of the foreign key (in the example above +city_id+), not the name of association itself. If you specify +city+ instead of +city_id+ Active Record will raise an error along the lines of <tt> ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) </tt> when you pass the +params+ hash to +Person.new+ or +update_attributes+. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential security ramifications of allowing users to edit foreign keys directly. You may wish to consider the use of +attr_protected+ and +attr_accessible+. For further details on this, see the "Ruby On Rails Security Guide":security.html#_mass_assignment. +WARNING: If you are using +select+ (or similar helpers such as +collection_select+, +select_tag+) to set a +belongs_to+ association you must pass the name of the foreign key (in the example above +city_id+), not the name of association itself. If you specify +city+ instead of +city_id+ Active Record will raise an error along the lines of <tt> ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) </tt> when you pass the +params+ hash to +Person.new+ or +update_attributes+. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential security ramifications of allowing users to edit foreign keys directly. You may wish to consider the use of +attr_protected+ and +attr_accessible+. For further details on this, see the "Ruby On Rails Security Guide":security.html#_mass_assignment. h4. Option Tags from a Collection of Arbitrary Objects @@ -513,7 +513,7 @@ The +:prefix+ option is the key used to retrieve the hash of date components fro h4(#select-model-object-helpers). Model Object Helpers +select_date+ does not work well with forms that update or create Active Record objects as Active Record expects each element of the +params+ hash to correspond to one attribute. -The model object helpers for dates and times submit parameters with special names, when Active Record sees parameters with such names it knows they must be combined with the other parameters and given to a constructor appropriate to the column type. For example: +The model object helpers for dates and times submit parameters with special names, when Active Record sees parameters with such names it knows they must be combined with the other parameters and given to a constructor appropriate to the column type. For example: <erb> <%= date_select :person, :birth_date %> diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index cd8ac3d6fd..ac709968d9 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -190,7 +190,7 @@ $ rails generate scaffold User name:string invoke test_unit create test/unit/helpers/users_helper_test.rb invoke stylesheets - create app/assets/stylesheets/scaffold.css.scss + create app/assets/stylesheets/scaffold.css </shell> Looking at this output, it's easy to understand how generators work in Rails 3.0 and above. The scaffold generator doesn't actually generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication. @@ -383,7 +383,7 @@ if yes?("Would you like to install Devise?") end </ruby> -In the above template we specify that the application relies on the +rspec-rails+ and +cucumber-rails+ gem so these two will be added to the +test+ group in the +Gemfile+. Then we pose a question to the user about whether or not they would like to install Devise. If the user replies "y" or "yes" to this question, then the template will add Devise to the +Gemfile+ outside of any group and then runs the +devise:install+ generator. This template then takes the users input and runs the +devise+ generator, with the user's answer from the last question being passed to this generator. +In the above template we specify that the application relies on the +rspec-rails+ and +cucumber-rails+ gem so these two will be added to the +test+ group in the +Gemfile+. Then we pose a question to the user about whether or not they would like to install Devise. If the user replies "y" or "yes" to this question, then the template will add Devise to the +Gemfile+ outside of any group and then runs the +devise:install+ generator. This template then takes the users input and runs the +devise+ generator, with the user's answer from the last question being passed to this generator. Imagine that this template was in a file called +template.rb+. We can use it to modify the outcome of the +rails new+ command by using the +-m+ option and passing in the filename: diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 3f9bd2b6da..366df9cd84 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -22,7 +22,7 @@ TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails 3. * The "RubyGems":http://rubyforge.org/frs/?group_id=126 packaging system * A working installation of the "SQLite3 Database":http://www.sqlite.org -Rails is a web application framework running on the Ruby programming language. If you have no prior experience with Ruby, you will find a very steep learning curve diving straight into Rails. There are some good free resources on the internet for learning Ruby, including: +Rails is a web application framework running on the Ruby programming language. If you have no prior experience with Ruby, you will find a very steep learning curve diving straight into Rails. There are some good free resources on the internet for learning Ruby, including: * "Mr. Neighborly's Humble Little Ruby Book":http://www.humblelittlerubybook.com * "Programming Ruby":http://www.ruby-doc.org/docs/ProgrammingRuby/ @@ -78,7 +78,7 @@ Rails ships as many individual components. h5. Action Pack -Action Pack is a single gem that contains Action Controller, Action View and Action Dispatch. The "VC" part of "MVC". +Action Pack is a single gem that contains Action Controller, Action View and Action Dispatch. The "VC" part of "MVC". h5. Action Controller @@ -98,7 +98,7 @@ Action Mailer is a framework for building e-mail services. You can use Action Ma h5. Active Model -Active Model provides a defined interface between the Action Pack gem services and Object Relationship Mapping gems such as Active Record. Active Model allows Rails to utilize other ORM frameworks in place of Active Record if your application needs this. +Active Model provides a defined interface between the Action Pack gem services and Object Relationship Mapping gems such as Active Record. Active Model allows Rails to utilize other ORM frameworks in place of Active Record if your application needs this. h5. Active Record @@ -153,7 +153,7 @@ TIP. If you're working on Windows, you can quickly install Ruby and Rails with " h4. Creating the Blog Application -The best way to use this guide is to follow each step as it happens, no code or step needed to make this example application has been left out, so you can literally follow along step by step. If you need to see the completed code, you can download it from "Getting Started Code":https://github.com/mikel/getting-started-code. +The best way to use this guide is to follow each step as it happens, no code or step needed to make this example application has been left out, so you can literally follow along step by step. If you need to see the completed code, you can download it from "Getting Started Code":https://github.com/mikel/getting-started-code. To begin, open a terminal, navigate to a folder where you have rights to create files, and type: @@ -184,7 +184,7 @@ In any case, Rails will create a folder in your working directory called <tt>blo |doc/|In-depth documentation for your application.| |lib/|Extended modules for your application (not covered in this guide).| |log/|Application log files.| -|public/|The only folder seen to the world as-is. This is where your images, JavaScript files, stylesheets (CSS), and other static files go.| +|public/|The only folder seen to the world as-is. This is where your images, JavaScript files, stylesheets (CSS), and other static files go.| |script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.| |test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html| |tmp/|Temporary files| @@ -290,7 +290,7 @@ This will fire up an instance of the WEBrick web server by default (Rails can al TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. In development mode, Rails does not generally require you to stop the server; changes you make in files will be automatically picked up by the server. -The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your Application's environment. +The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your Application's environment. h4. Say "Hello", Rails @@ -310,7 +310,7 @@ Rails will create several files for you, including +app/views/home/index.html.er h4. Setting the Application Home Page -Now that we have made the controller and view, we need to tell Rails when we want "Hello Rails" to show up. In our case, we want it to show up when we navigate to the root URL of our site, "http://localhost:3000":http://localhost:3000, instead of the "Welcome Aboard" smoke test. +Now that we have made the controller and view, we need to tell Rails when we want "Hello Rails" to show up. In our case, we want it to show up when we navigate to the root URL of our site, "http://localhost:3000":http://localhost:3000, instead of the "Welcome Aboard" smoke test. The first step to doing this is to delete the default page from your application: @@ -394,7 +394,7 @@ class CreatePosts < ActiveRecord::Migration end </ruby> -The above migration creates two methods, +up+, called when you run this migration into the database, and +down+ in case you need to reverse the changes made by this migration at a later date. The +up+ command in this case creates a +posts+ table with two string columns and a text column. It also creates two timestamp fields to track record creation and updating. More information about Rails migrations can be found in the "Rails Database Migrations":migrations.html guide. +The above migration creates two methods, +up+, called when you run this migration into the database, and +down+ in case you need to reverse the changes made by this migration at a later date. The +up+ command in this case creates a +posts+ table with two string columns and a text column. It also creates two timestamp fields to track record creation and updating. More information about Rails migrations can be found in the "Rails Database Migrations":migrations.html guide. At this point, you can use a rake command to run the migration: @@ -548,7 +548,7 @@ This view iterates over the contents of the +@posts+ array to display content an * +link_to+ builds a hyperlink to a particular destination * +edit_post_path+ and +new_post_path+ are helpers that Rails provides as part of RESTful routing. You'll see a variety of these helpers for the different actions that the controller includes. -NOTE. In previous versions of Rails, you had to use +<%=h post.name %>+ so that any HTML would be escaped before being inserted into the page. In Rails 3.0, this is now the default. To get unescaped HTML, you now use +<%= raw post.name %>+. +NOTE. In previous versions of Rails, you had to use +<%=h post.name %>+ so that any HTML would be escaped before being inserted into the page. In Rails 3.0, this is now the default. To get unescaped HTML, you now use +<%= raw post.name %>+. TIP: For more details on the rendering process, see "Layouts and Rendering in Rails":layouts_and_rendering.html. @@ -600,7 +600,7 @@ The +new.html.erb+ view displays this empty Post to the user: <%= link_to 'Back', posts_path %> </erb> -The +<%= render 'form' %>+ line is our first introduction to _partials_ in Rails. A partial is a snippet of HTML and Ruby code that can be reused in multiple locations. In this case, the form used to make a new post, is basically identical to a form used to edit a post, both have text fields for the name and title and a text area for the content with a button to make a new post or update the existing post. +The +<%= render 'form' %>+ line is our first introduction to _partials_ in Rails. A partial is a snippet of HTML and Ruby code that can be reused in multiple locations. In this case, the form used to make a new post, is basically identical to a form used to edit a post, both have text fields for the name and title and a text area for the content with a button to make a new post or update the existing post. If you take a look at +views/posts/_form.html.erb+ file, you will see the following: @@ -873,7 +873,7 @@ TIP: For more information on Active Record associations, see the "Active Record h4. Adding a Route for Comments -As with the +home+ controller, we will need to add a route so that Rails knows where we would like to navigate to see +comments+. Open up the +config/routes.rb+ file again, you will see an entry that was added automatically for +posts+ near the top by the scaffold generator, +resources :posts+, edit it as follows: +As with the +home+ controller, we will need to add a route so that Rails knows where we would like to navigate to see +comments+. Open up the +config/routes.rb+ file again, you will see an entry that was added automatically for +posts+ near the top by the scaffold generator, +resources :posts+, edit it as follows: <ruby> resources :posts do @@ -901,7 +901,7 @@ This creates four files and one empty directory: * +test/unit/helpers/comments_helper_test.rb+ - The unit tests for the helper * +app/views/comments/+ - Views of the controller are stored here -Like with any blog, our readers will create their comments directly after reading the post, and once they have added their comment, will be sent back to the post show page to see their comment now listed. Due to this, our +CommentsController+ is there to provide a method to create comments and delete SPAM comments when they arrive. +Like with any blog, our readers will create their comments directly after reading the post, and once they have added their comment, will be sent back to the post show page to see their comment now listed. Due to this, our +CommentsController+ is there to provide a method to create comments and delete SPAM comments when they arrive. So first, we'll wire up the Post show template (+/app/views/posts/show.html.erb+) to let us make a new comment: @@ -1078,7 +1078,7 @@ Then in the +app/views/posts/show.html.erb+ you can change it to look like the f <%= link_to 'Back to Posts', posts_path %> | </erb> -This will now render the partial in +app/views/comments/_comment.html.erb+ once for each comment that is in the +@post.comments+ collection. As the +render+ method iterates over the <tt>@post.comments</tt> collection, it assigns each comment to a local variable named the same as the partial, in this case +comment+ which is then available in the partial for us to show. +This will now render the partial in +app/views/comments/_comment.html.erb+ once for each comment that is in the +@post.comments+ collection. As the +render+ method iterates over the <tt>@post.comments</tt> collection, it assigns each comment to a local variable named the same as the partial, in this case +comment+ which is then available in the partial for us to show. h4. Rendering a Partial Form @@ -1138,7 +1138,7 @@ The +@post+ object is available to any partials rendered in the view because we h3. Deleting Comments -Another important feature on a blog is being able to delete SPAM comments. To do this, we need to implement a link of some sort in the view and a +DELETE+ action in the +CommentsController+. +Another important feature on a blog is being able to delete SPAM comments. To do this, we need to implement a link of some sort in the view and a +DELETE+ action in the +CommentsController+. So first, let's add the delete link in the +app/views/comments/_comment.html.erb+ partial: @@ -1312,7 +1312,7 @@ Note that we have changed the +f+ in +form_for(@post) do |f|+ to +post_form+ to This example shows another option of the render helper, being able to pass in local variables, in this case, we want the local variable +form+ in the partial to refer to the +post_form+ object. -We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make sure there is a new tag ready to have it's name filled in by the user. If you do not build the new tag, then the form will not appear as there is no new Tag object ready to create. +We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make sure there is a new tag ready to have it's name filled in by the user. If you do not build the new tag, then the form will not appear as there is no new Tag object ready to create. Now create the folder <tt>app/views/tags</tt> and make a file in there called <tt>_form.html.erb</tt> which contains the form for the tag: @@ -1373,7 +1373,7 @@ However, that method call <tt>@post.tags.map { |t| t.name }.join(", ")</tt> is a h3. View Helpers -View Helpers live in <tt>app/helpers</tt> and provide small snippets of reusable code for views. In our case, we want a method that strings a bunch of objects together using their name attribute and joining them with a comma. As this is for the Post show template, we put it in the PostsHelper. +View Helpers live in <tt>app/helpers</tt> and provide small snippets of reusable code for views. In our case, we want a method that strings a bunch of objects together using their name attribute and joining them with a comma. As this is for the Post show template, we put it in the PostsHelper. Open up <tt>app/helpers/posts_helper.rb</tt> and add the following: diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 3e7e396e8d..5478a80567 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -91,7 +91,7 @@ This means, that in the +:en+ locale, the key _hello_ will map to the _Hello wor The I18n library will use *English* as a *default locale*, i.e. if you don't set a different locale, +:en+ will be used for looking up translations. -NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-UK+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cz+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-UK+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-UK+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it. +NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-UK+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cz+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-UK+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-UK+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it. The *translations load path* (+I18n.load_path+) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you. @@ -441,7 +441,7 @@ Do check the "Rails i18n Wiki":http://rails-i18n.org/wiki for list of tools avai h3. Overview of the I18n API Features -You should have good understanding of using the i18n library now, knowing all necessary aspects of internationalizing a basic Rails application. In the following chapters, we'll cover it's features in more depth. +You should have good understanding of using the i18n library now, knowing all necessary aspects of internationalizing a basic Rails application. In the following chapters, we'll cover it's features in more depth. Covered are features like these: @@ -520,7 +520,7 @@ I18n.t 'activerecord.errors.messages' h5. "Lazy" Lookup -Rails 2.3 implements a convenient way to look up the locale inside _views_. When you have the following dictionary: +Rails implements a convenient way to look up the locale inside _views_. When you have the following dictionary: <yaml> es: @@ -863,7 +863,7 @@ If you find anything missing or wrong in this guide, please file a ticket on our h3. Contributing to Rails I18n -I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first, and only then cherry-picking the best-of-bread of most widely useful features for inclusion in the core. +I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first, and only then cherry-picking the best-of-breed of most widely useful features for inclusion in the core. Thus we encourage everybody to experiment with new ideas and features in plugins or other libraries and make them available to the community. (Don't forget to announce your work on our "mailing list":http://groups.google.com/group/rails-i18n!) diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index af46beee56..b48488d8a2 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -17,7 +17,7 @@ Ruby on Rails Guides <% else %> <p> These are the new guides for Rails 3. The guides for Rails 2.3 are still available - at <a href="http://guides.rubyonrails.org/v2.3.8/">http://guides.rubyonrails.org/v2.3.8/</a>. + at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>. </p> <% end %> <p> diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 7c01f01b24..638830cd83 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -468,7 +468,7 @@ h4. +config/application.rb+ This file requires +config/boot.rb+, but only if it hasn't been required before, which would be the case in +rails server+ but *wouldn't* be the case with Passenger. -Then the fun begins! +Then the fun begins! h3. Loading Rails @@ -592,7 +592,11 @@ This file defines the behavior of the +ActiveSupport::Deprecation+ module, setti h4. +activesupport/lib/active_support/notifications.rb+ -TODO: document +ActiveSupport::Notifications+. +This file defines the +ActiveSupport::Notifications+ module. Notifications provides an instrumentation API for Ruby, shipping with a queue implementation that consumes and publish events to log subscribers in a thread. + +The "API documentation":http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html for +ActiveSupport::Notifications+ explains the usage of this module, including the methods that it defines. + +The file required in +active_support/notifications.rb+ is +active_support/core_ext/module/delegation+ which is documented in the "Active Support Core Extensions Guide":http://guides.rubyonrails.org/active_support_core_extensions.html#method-delegation. h4. +activesupport/core_ext/array/wrap+ @@ -660,7 +664,7 @@ The +active_support/inflector/methods+ file has already been required by +active h4. +activesupport/lib/active_support/inflector/inflections.rb+ -This file references the +ActiveSupport::Inflector+ constant which isn't loaded by this point. But there were autoloads set up in +activesupport/lib/active_support.rb+ which will load the file which loads this constant and so then it will be defined. Then this file defines pluralization and singularization rules for words in Rails. This is how Rails knows how to pluralize "tomato" to "tomatoes". +This file references the +ActiveSupport::Inflector+ constant which isn't loaded by this point. But there were autoloads set up in +activesupport/lib/active_support.rb+ which will load the file which loads this constant and so then it will be defined. Then this file defines pluralization and singularization rules for words in Rails. This is how Rails knows how to pluralize "tomato" to "tomatoes". h4. +activesupport/lib/active_support/inflector/transliterate.rb+ @@ -694,7 +698,7 @@ h4. Back to +railties/lib/rails/plugin.rb+ The next file required in this is a core extension from Active Support called +array/conversions+ which is covered in "this section":http://guides.rubyonrails.org/active_support_core_extensions.html#array-conversions of the Active Support Core Extensions Guide. -Once that file has finished loading, the +Rails::Plugin+ class is defined. +Once that file has finished loading, the +Rails::Plugin+ class is defined. h4. Back to +railties/lib/rails/application.rb+ @@ -704,7 +708,7 @@ Once this file's done then we go back to the +railties/lib/rails.rb+ file, which h4. +railties/lib/rails/version.rb+ -Much like +active_support/version+, this file defines the +VERSION+ constant which has a +STRING+ constant on it which returns the current version of Rails. +Much like +active_support/version+, this file defines the +VERSION+ constant which has a +STRING+ constant on it which returns the current version of Rails. Once this file has finished loading we go back to +railties/lib/rails.rb+ which then requires +active_support/railtie.rb+. @@ -922,7 +926,7 @@ This file defines the +ActionDispatch::Railtie+ class, but not before requiring h4. +activesupport/lib/action_dispatch.rb+ -This file attempts to locate the +active_support+ and +active_model+ libraries by looking a couple of directories back from the current file and then adds the +active_support+ and +active_model+ +lib+ directories to the load path, but only if they aren't already, which they are. +This file attempts to locate the +active_support+ and +active_model+ libraries by looking a couple of directories back from the current file and then adds the +active_support+ and +active_model+ +lib+ directories to the load path, but only if they aren't already, which they are. <ruby> activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__) @@ -1005,7 +1009,7 @@ The loading of this file finishes the loading of +active_model+ and so we go bac h4. Back to +activesupport/lib/action_dispatch.rb+ -The remainder of this file requires the +rack+ file from the Rack gem which defines the +Rack+ module. After +rack+, there's autoloads defined for the +Rack+, +ActionDispatch+, +ActionDispatch::Http+, +ActionDispatch::Session+. A new method called +autoload_under+ is used here, and this simply prefixes the files where the modules are autoloaded from with the path specified. For example here: +The remainder of this file requires the +rack+ file from the Rack gem which defines the +Rack+ module. After +rack+, there's autoloads defined for the +Rack+, +ActionDispatch+, +ActionDispatch::Http+, +ActionDispatch::Session+. A new method called +autoload_under+ is used here, and this simply prefixes the files where the modules are autoloaded from with the path specified. For example here: <ruby> autoload_under 'testing' do @@ -1108,4 +1112,4 @@ However the require after these is to a file that hasn't yet been loaded, +actio h4. +actionpack/lib/action_view.rb+ -+action_view.rb+ ++action_view.rb+ diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index 8dab578e6b..620df970dc 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -394,7 +394,7 @@ end Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout: -You can also decide the layout by passing a Proc object, the block you give the Proc will be given the +controller+ instance, so you can make decisions based on the current request. For example: +You can also decide the layout by passing a Proc object, the block you give the Proc will be given the +controller+ instance, so you can make decisions based on the current request. For example: <ruby> class ProductsController < ApplicationController @@ -572,7 +572,7 @@ With this code, the browser will make a fresh request for the index page, the co The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen. -While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be: +While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be: <ruby> def index @@ -860,7 +860,7 @@ Produces <video src="/videos/movie.ogg" /> </erb> -Like an +image_tag+ you can supply a path, either absolute, or relative to the +public/videos+ directory. Additionally you can specify the +:size => "#{width}x#{height}"+ option just like an +image_tag+. Video tags can also have any of the HTML options specified at the end (+id+, +class+ et al). +Like an +image_tag+ you can supply a path, either absolute, or relative to the +public/videos+ directory. Additionally you can specify the +:size => "#{width}x#{height}"+ option just like an +image_tag+. Video tags can also have any of the HTML options specified at the end (+id+, +class+ et al). The video tag also supports all of the +<video>+ HTML options through the HTML options hash, including: @@ -1133,7 +1133,7 @@ You can also pass in arbitrary local variables to any partial you are rendering Would render a partial +_products.html.erb+ once for each instance of +product+ in the +@products+ instance variable passing the instance to the partial as a local variable called +item+ and to each partial, make the local variable +title+ available with the value +Products Page+. -TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered. This does not work in conjunction with the +:as => :value+ option. +TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered. This does not work in conjunction with the +:as => :value+ option. You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option: diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 57e6bcd123..bf5d4d3e4d 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -284,7 +284,7 @@ change_table :products do |t| t.rename :upccode, :upc_code end </ruby> -removes the +description+ and +name+ columns, creates a +part_number+ column and adds an index on it. Finally it renames the +upccode+ column. This is the same as doing +removes the +description+ and +name+ columns, creates a +part_number+ column and adds an index on it. Finally it renames the +upccode+ column. This is the same as doing <ruby> remove_column :products, :description @@ -335,7 +335,7 @@ NOTE: The +references+ helper does not actually create foreign key constraints f If the helpers provided by Active Record aren't enough you can use the +execute+ function to execute arbitrary SQL. -For more details and examples of individual methods check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+). +For more details and examples of individual methods check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+). h4. Writing Your +down+ Method diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile index 2d9821e627..d486e8ade3 100644 --- a/railties/guides/source/plugins.textile +++ b/railties/guides/source/plugins.textile @@ -17,8 +17,8 @@ This guide describes how to build a test-driven plugin that will: * Add methods to ActiveRecord::Base in the tradition of the 'acts_as' plugins * Give you information about where to put generators in your plugin. -For the purpose of this guide pretend for a moment that you are an avid bird watcher. -Your favorite bird is the Yaffle, and you want to create a plugin that allows other developers to share in the Yaffle +For the purpose of this guide pretend for a moment that you are an avid bird watcher. +Your favorite bird is the Yaffle, and you want to create a plugin that allows other developers to share in the Yaffle goodness. endprologue. @@ -27,21 +27,21 @@ h3. Setup h4. Generating the Plugin Skeleton -Rails currently ships with a generator to generate a plugin within a Rails application. Help text is available that will explain +Rails currently ships with a generator to generate a plugin within a Rails application. Help text is available that will explain how this generator works. <shell> $ rails generate plugin --help </shell> -This generator places the plugin into the vendor/plugins directory. +This generator places the plugin into the vendor/plugins directory. -Vendored plugins are useful for quickly prototyping your plugin but current thinking in the Rails community is shifting towards +Vendored plugins are useful for quickly prototyping your plugin but current thinking in the Rails community is shifting towards packaging plugins as gems, especially with the inclusion of Bundler as the Rails dependency manager. Packaging a plugin as a gem may be overkill for any plugins that will not be shared across projects but doing so from the start makes it easier to share the plugin going forward without adding too much additional overhead during development. Rails 3.1 will ship with a plugin generator that will default to setting up a plugin -as a gem. This tutorial will begin to bridge that gap by demonstrating how to create a gem based plugin using the +as a gem. This tutorial will begin to bridge that gap by demonstrating how to create a gem based plugin using the "Enginex gem":http://www.github.com/josevalim/enginex. <shell> @@ -69,7 +69,7 @@ h3. Extending Core Classes This section will explain how to add a method to String that will be available anywhere in your rails application. -In this example you will add a method to String named +to_squawk+. To begin, create a new test file with a few assertions: +In this example you will add a method to String named +to_squawk+. To begin, create a new test file with a few assertions: <ruby> # yaffle/test/core_ext_test.rb @@ -83,7 +83,7 @@ class CoreExtTest < Test::Unit::TestCase end </ruby> -Run +rake+ to run the test. This test should fail because we haven't implemented the +to_squak+ method: +Run +rake+ to run the test. This test should fail because we haven't implemented the +to_squak+ method: <shell> 1) Error: @@ -133,7 +133,7 @@ $ rails console h3. Add an "acts_as" Method to Active Record -A common pattern in plugins is to add a method called 'acts_as_something' to models. In this case, you +A common pattern in plugins is to add a method called 'acts_as_something' to models. In this case, you want to write a method called 'acts_as_yaffle' that adds a 'squawk' method to your Active Record models. To begin, set up your files so that you have: @@ -169,9 +169,9 @@ end h4. Add a Class Method -This plugin will expect that you've added a method to your model named 'last_squawk'. However, the -plugin users might have already defined a method on their model named 'last_squawk' that they use -for something else. This plugin will allow the name to be changed by adding a class method called 'yaffle_text_field'. +This plugin will expect that you've added a method to your model named 'last_squawk'. However, the +plugin users might have already defined a method on their model named 'last_squawk' that they use +for something else. This plugin will allow the name to be changed by adding a class method called 'yaffle_text_field'. To start out, write a failing test that shows the behavior you'd like: @@ -210,7 +210,7 @@ When you run +rake+, you should see the following: </shell> This tells us that we don't have the necessary models (Hickwall and Wickwall) that we are trying to test. -We can easily generate these models in our "dummy" Rails application by running the following commands from the +We can easily generate these models in our "dummy" Rails application by running the following commands from the test/dummy directory: <shell> @@ -220,7 +220,7 @@ $ rails generate model Wickwall last_squak:string last_tweet:string </shell> Now you can create the necessary database tables in your testing database by navigating to your dummy app -and migrating the database. First +and migrating the database. First <shell> $ cd test/dummy @@ -319,7 +319,7 @@ When you run +rake+ you should see the tests all pass: h4. Add an Instance Method -This plugin will add a method named 'squawk' to any Active Record objects that call 'acts_as_yaffle'. The 'squawk' +This plugin will add a method named 'squawk' to any Active Record objects that call 'acts_as_yaffle'. The 'squawk' method will simply set the value of one of the fields in the database. To start out, write a failing test that shows the behavior you'd like: @@ -352,7 +352,7 @@ class ActsAsYaffleTest < Test::Unit::TestCase end </ruby> -Run the test to make sure the last two tests fail the an error that contains "NoMethodError: undefined method `squawk'", +Run the test to make sure the last two tests fail the an error that contains "NoMethodError: undefined method `squawk'", then update 'acts_as_yaffle.rb' to look like this: <ruby> @@ -387,18 +387,18 @@ Run +rake+ one final time and you should see: 7 tests, 7 assertions, 0 failures, 0 errors, 0 skips </shell> -NOTE: The use of +write_attribute+ to write to the field in model is just one example of how a plugin can -interact with the model, and will not always be the right method to use. For example, you could also +NOTE: The use of +write_attribute+ to write to the field in model is just one example of how a plugin can +interact with the model, and will not always be the right method to use. For example, you could also use +send("#{self.class.yaffle_text_field}=", string.to_squawk)+. h3. Generators -Generators can be included in your gem simply by creating them in a lib/generators directory of your plugin. More information about +Generators can be included in your gem simply by creating them in a lib/generators directory of your plugin. More information about the creation of generators can be found in the "Generators Guide":generators.html h3. Publishing your Gem -Gem plugins in progress can be easily be shared from any Git repository. To share the Yaffle gem with others, simply +Gem plugins in progress can be easily be shared from any Git repository. To share the Yaffle gem with others, simply commit the code to a Git repository (like Github) and add a line to the Gemfile of the any application: <ruby> @@ -412,7 +412,7 @@ For more information about publishing gems to RubyGems, see: "http://blog.thepet h3. Non-Gem Plugins -Non-gem plugins are useful for functionality that won't be shared with another project. Keeping your custom functionality in the +Non-gem plugins are useful for functionality that won't be shared with another project. Keeping your custom functionality in the vendor/plugins directory un-clutters the rest of the application. Move the directory that you created for the gem based plugin into the vendor/plugins directory of a generated Rails application, create a vendor/plugins/yaffle/init.rb file that contains "require 'yaffle'" and everything will still work. @@ -423,7 +423,7 @@ Move the directory that you created for the gem based plugin into the vendor/plu require 'yaffle' </ruby> -You can test this by changing to the Rails application that you added the plugin to and starting a rails console. Once in the +You can test this by changing to the Rails application that you added the plugin to and starting a rails console. Once in the console we can check to see if the String has an instance method of to_squawk. <shell> $ cd my_app @@ -435,7 +435,7 @@ You can also remove the .gemspec, Gemfile and Gemfile.lock files as they will no h3. RDoc Documentation -Once your plugin is stable and you are ready to deploy do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy. +Once your plugin is stable and you are ready to deploy do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy. The first step is to update the README file with detailed information about how to use your plugin. A few key things to include are: diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile index 8e51f9e23b..388d8eea3e 100644 --- a/railties/guides/source/rails_application_templates.textile +++ b/railties/guides/source/rails_application_templates.textile @@ -11,19 +11,19 @@ endprologue. h3. Usage -To apply a template, you need to provide the Rails generator with the location of the template you wish to apply, using -m option : +To apply a template, you need to provide the Rails generator with the location of the template you wish to apply, using -m option: <shell> $ rails new blog -m ~/template.rb </shell> -It's also possible to apply a template using a URL : +It's also possible to apply a template using a URL: <shell> $ rails new blog -m https://gist.github.com/755496.txt </shell> -Alternatively, you can use the rake task +rails:template+ to apply a template to an existing Rails application : +Alternatively, you can use the rake task +rails:template+ to apply a template to an existing Rails application: <shell> $ rake rails:template LOCATION=~/template.rb @@ -31,7 +31,7 @@ $ rake rails:template LOCATION=~/template.rb h3. Template API -Rails templates API is very self explanatory and easy to understand. Here's an example of a typical Rails template : +Rails templates API is very self explanatory and easy to understand. Here's an example of a typical Rails template: <ruby> # template.rb @@ -45,20 +45,20 @@ git :add => "." git :commit => "-a -m 'Initial commit'" </ruby> -The following sections outlines the primary methods provided by the API : +The following sections outlines the primary methods provided by the API: h4. gem(name, options = {}) Adds a +gem+ entry for the supplied gem to the generated application’s +Gemfile+. -For example, if your application depends on the gems +bj+ and +nokogiri+ : +For example, if your application depends on the gems +bj+ and +nokogiri+: <ruby> gem "bj" gem "nokogiri" </ruby> -Please note that this will NOT install the gems for you. So you may want to run the +rake gems:install+ task too : +Please note that this will NOT install the gems for you. So you may want to run the +rake gems:install+ task too: <ruby> rake "gems:install" @@ -80,13 +80,13 @@ h4. plugin(name, options = {}) Installs a plugin to the generated application. -Plugin can be installed from Git : +Plugin can be installed from Git: <ruby> plugin 'authentication', :git => 'git://github.com/foor/bar.git' </ruby> -You can even install plugins as git submodules : +You can even install plugins as git submodules: <ruby> plugin 'authentication', :git => 'git://github.com/foor/bar.git', @@ -95,7 +95,7 @@ plugin 'authentication', :git => 'git://github.com/foor/bar.git', Please note that you need to +git :init+ before you can install a plugin as a submodule. -Or use plain old SVN : +Or use plain old SVN: <ruby> plugin 'usingsvn', :svn => 'svn://example.com/usingsvn/trunk' @@ -105,7 +105,7 @@ h4. vendor/lib/file/initializer(filename, data = nil, &block) Adds an initializer to the generated application’s +config/initializers+ directory. -Lets say you like using +Object#not_nil?+ and +Object#not_blank?+ : +Lets say you like using +Object#not_nil?+ and +Object#not_blank?+: <ruby> initializer 'bloatlol.rb', <<-CODE @@ -123,7 +123,7 @@ CODE Similarly +lib()+ creates a file in the +lib/+ directory and +vendor()+ creates a file in the +vendor/+ directory. -There is even +file()+, which accepts a relative path from +Rails.root+ and creates all the directories/file needed : +There is even +file()+, which accepts a relative path from +Rails.root+ and creates all the directories/file needed: <ruby> file 'app/components/foo.rb', <<-CODE @@ -136,7 +136,7 @@ That’ll create +app/components+ directory and put +foo.rb+ in there. h4. rakefile(filename, data = nil, &block) -Creates a new rake file under +lib/tasks+ with the supplied tasks : +Creates a new rake file under +lib/tasks+ with the supplied tasks: <ruby> rakefile("bootstrap.rake") do @@ -154,7 +154,7 @@ The above creates +lib/tasks/bootstrap.rake+ with a +boot:strap+ rake task. h4. generate(what, args) -Runs the supplied rails generator with given arguments. For example, I love to scaffold some whenever I’m playing with Rails : +Runs the supplied rails generator with given arguments. For example, I love to scaffold some whenever I’m playing with Rails: <ruby> generate(:scaffold, "person", "name:string", "address:text", "age:number") @@ -162,7 +162,7 @@ generate(:scaffold, "person", "name:string", "address:text", "age:number") h4. run(command) -Executes an arbitrary command. Just like the backticks. Let's say you want to remove the +public/index.html+ file : +Executes an arbitrary command. Just like the backticks. Let's say you want to remove the +public/index.html+ file: <ruby> run "rm public/index.html" @@ -170,19 +170,19 @@ run "rm public/index.html" h4. rake(command, options = {}) -Runs the supplied rake tasks in the Rails application. Let's say you want to migrate the database : +Runs the supplied rake tasks in the Rails application. Let's say you want to migrate the database: <ruby> rake "db:migrate" </ruby> -You can also run rake tasks with a different Rails environment : +You can also run rake tasks with a different Rails environment: <ruby> rake "db:migrate", :env => 'production' </ruby> -Or even use sudo : +Or even use sudo: <ruby> rake "gems:install", :sudo => true @@ -190,7 +190,7 @@ rake "gems:install", :sudo => true h4. route(routing_code) -This adds a routing entry to the +config/routes.rb+ file. In above steps, we generated a person scaffold and also removed +public/index.html+. Now to make +PeopleController#index+ as the default page for the application : +This adds a routing entry to the +config/routes.rb+ file. In above steps, we generated a person scaffold and also removed +public/index.html+. Now to make +PeopleController#index+ as the default page for the application: <ruby> route "root :to => 'person#index'" @@ -208,7 +208,7 @@ end h4. ask(question) -+ask()+ gives you a chance to get some feedback from the user and use it in your templates. Lets say you want your user to name the new shiny library you’re adding : ++ask()+ gives you a chance to get some feedback from the user and use it in your templates. Lets say you want your user to name the new shiny library you’re adding: <ruby> lib_name = ask("What do you want to call the shiny library ?") @@ -222,7 +222,7 @@ CODE h4. yes?(question) or no?(question) -These methods let you ask questions from templates and decide the flow based on the user’s answer. Lets say you want to freeze rails only if the user want to : +These methods let you ask questions from templates and decide the flow based on the user’s answer. Lets say you want to freeze rails only if the user want to: <ruby> rake("rails:freeze:gems") if yes?("Freeze rails gems ?") @@ -231,7 +231,7 @@ no?(question) acts just the opposite. h4. git(:must => "-a love") -Rails templates let you run any git command : +Rails templates let you run any git command: <ruby> git :init diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 58b75b9a1d..95b877aecf 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -321,7 +321,7 @@ resources :photos do end </ruby> -This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers. +This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers. Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also pass +:on+ to a route, eliminating the block: @@ -421,7 +421,7 @@ You do not need to explicitly use the +:controller+ and +:action+ symbols within match 'photos/:id' => 'photos#show' </ruby> -With this route, Rails will match an incoming path of +/photos/12+ to the +show+ action of +PhotosController+. +With this route, Rails will match an incoming path of +/photos/12+ to the +show+ action of +PhotosController+. You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that you do not specify as dynamic segments. For example: diff --git a/railties/guides/source/ruby_on_rails_guides_guidelines.textile b/railties/guides/source/ruby_on_rails_guides_guidelines.textile index 8e55780dca..26a5a4c3c9 100644 --- a/railties/guides/source/ruby_on_rails_guides_guidelines.textile +++ b/railties/guides/source/ruby_on_rails_guides_guidelines.textile @@ -13,7 +13,7 @@ h3. Prologue Each guide should start with motivational text at the top (that's the little introduction in the blue area.) The prologue should tell the reader what the guide is about, and what they will learn. See for example the "Routing Guide":routing.html. h3. Titles - + The title of every guide uses +h2+, guide sections use +h3+, subsections +h4+, etc. Capitalize all words except for internal articles, prepositions, conjunctions, and forms of the verb to be: diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index c9dc1c2d7c..f4c1bde5b1 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -147,7 +147,7 @@ reset_session If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _(highlight)you have to transfer them to the new session_. -Another countermeasure is to _(highlight)save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _(highlight)These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way. +Another countermeasure is to _(highlight)save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _(highlight)These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way. h4. Session Expiry @@ -238,7 +238,7 @@ Or the attacker places the code into the onmouseover event handler of an image: <img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." /> </html> -There are many other possibilities, including Ajax to attack the victim in the background.
The _(highlight)solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller: +There are many other possibilities, including Ajax to attack the victim in the background.
The _(highlight)solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller: <ruby> protect_from_forgery :secret => "123456789012345678901234567890..." @@ -394,7 +394,7 @@ params[:user] # => {:name => “ow3ned”, :admin => true} So if you create a new user using mass-assignment, it may be too easy to become an administrator. -Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3. The +accepts_nested_attributes_for+ declaration provides us the ability to extend mass assignment to model associations (+has_many+, +has_one+, +has_and_belongs_to_many+). For example: +Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3. The +accepts_nested_attributes_for+ declaration provides us the ability to extend mass assignment to model associations (+has_many+, +has_one+, +has_and_belongs_to_many+). For example: <ruby> class Person < ActiveRecord::Base @@ -434,13 +434,13 @@ params[:user] # => {:name => "ow3ned", :admin => true} @user.admin # => true </ruby> -A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer: +A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer: <ruby> ActiveRecord::Base.send(:attr_accessible, nil) </ruby> -This will create an empty whitelist of attributes available for mass assignment for all models in your app. As such, your models will need to explicitly whitelist accessible parameters by using an +attr_accessible+ declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to insert this initializer, run your tests, and expose each attribute (via +attr_accessible+) as dictated by your failing tests. +This will create an empty whitelist of attributes available for mass assignment for all models in your app. As such, your models will need to explicitly whitelist accessible parameters by using an +attr_accessible+ declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to insert this initializer, run your tests, and expose each attribute (via +attr_accessible+) as dictated by your failing tests. h3. User Management diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index e2317661ea..9b1ef22b97 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -415,8 +415,8 @@ NOTE: +assert_valid(record)+ has been deprecated. Please use +assert(record.vali |_.Assertion |_.Purpose| |+assert_valid(record)+ |Ensures that the passed record is valid by Active Record standards and returns any error messages if it is not.| -|+assert_difference(expressions, difference = 1, message = nil) {...}+ |Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.| -|+assert_no_difference(expressions, message = nil, &block)+ |Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| +|+assert_difference(expressions, difference = 1, message = nil) {...}+ |Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.| +|+assert_no_difference(expressions, message = nil, &block)+ |Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| |+assert_recognizes(expected_options, path, extras={}, message=nil)+ |Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.| |+assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)+ |Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.| |+assert_response(type, message = nil)+ |Asserts that the response comes with a specific status code. You can specify +:success+ to indicate 200, +:redirect+ to indicate 300-399, +:missing+ to indicate 404, or +:error+ to match the 500-599 range| |