Merge branch 'master' of git@github.com:rails/rails
1
.gitignore
vendored
@ -14,6 +14,7 @@ railties/pkg
|
||||
railties/test/500.html
|
||||
railties/doc/guides/html/images
|
||||
railties/doc/guides/html/stylesheets
|
||||
railties/guides/output
|
||||
*.rbc
|
||||
*.swp
|
||||
*.swo
|
||||
|
@ -1,3 +1,8 @@
|
||||
*Edge*
|
||||
|
||||
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
|
||||
|
||||
|
||||
*2.3.0 [RC1] (February 1st, 2009)*
|
||||
|
||||
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
|
||||
|
@ -672,7 +672,7 @@ def create_mail
|
||||
def perform_delivery_smtp(mail)
|
||||
destinations = mail.destinations
|
||||
mail.ready_to_send
|
||||
sender = mail['return-path'] || mail.from
|
||||
sender = (mail['return-path'] && mail['return-path'].spec) || mail.from
|
||||
|
||||
smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
|
||||
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
|
||||
|
@ -938,6 +938,7 @@ def test_return_path_with_deliver
|
||||
ActionMailer::Base.delivery_method = :smtp
|
||||
TestMailer.deliver_return_path
|
||||
assert_match %r{^Return-Path: <another@somewhere.test>}, MockSMTP.deliveries[0][0]
|
||||
assert_equal "another@somewhere.test", MockSMTP.deliveries[0][1].to_s
|
||||
end
|
||||
|
||||
def test_body_is_stored_as_an_ivar
|
||||
|
@ -1,5 +1,7 @@
|
||||
*Edge*
|
||||
|
||||
* Fix a syntax error in current_page?() that was prevent matches against URL's with multiple query parameters #1385, #1868 [chris finne/Andrew White]
|
||||
|
||||
* Added localized rescue template when I18n.locale is set (ex: public/404.da.html) #1835 [José Valim]
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@ def define_dispatcher_callbacks(cache_classes)
|
||||
unless cache_classes
|
||||
# Development mode callbacks
|
||||
before_dispatch :reload_application
|
||||
after_dispatch :cleanup_application
|
||||
|
||||
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
|
||||
end
|
||||
@ -93,11 +92,9 @@ def reload_application
|
||||
run_callbacks :prepare_dispatch
|
||||
|
||||
Routing::Routes.reload
|
||||
end
|
||||
|
||||
# Cleanup the application by clearing out loaded classes so they can
|
||||
# be reloaded on the next request without restarting the server.
|
||||
def cleanup_application
|
||||
# Cleanup the application by clearing out loaded classes so they can
|
||||
# be reloaded on the next request without restarting the server.
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
ActiveSupport::Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
|
@ -173,7 +173,7 @@ def layout_conditions #:nodoc:
|
||||
end
|
||||
|
||||
def default_layout(format) #:nodoc:
|
||||
layout = read_inheritable_attribute(:layout)
|
||||
layout = read_inheritable_attribute(:layout) unless format == :js
|
||||
return layout unless read_inheritable_attribute(:auto_layout)
|
||||
find_layout(layout, format)
|
||||
end
|
||||
|
@ -58,9 +58,28 @@ def loaded?
|
||||
end
|
||||
|
||||
def load!
|
||||
@id, session = @by.send(:load_session, @env)
|
||||
replace(session)
|
||||
@loaded = true
|
||||
stale_session_check! do
|
||||
@id, session = @by.send(:load_session, @env)
|
||||
replace(session)
|
||||
@loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
def stale_session_check!
|
||||
yield
|
||||
rescue ArgumentError => argument_error
|
||||
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
||||
begin
|
||||
# Note that the regexp does not allow $1 to end with a ':'
|
||||
$1.constantize
|
||||
rescue LoadError, NameError => const_error
|
||||
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
||||
end
|
||||
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -516,7 +516,8 @@ def self.cache_asset_timestamps=(value)
|
||||
def compute_public_path(source, dir, ext = nil, include_host = true)
|
||||
has_request = @controller.respond_to?(:request)
|
||||
|
||||
if ext && (File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")))
|
||||
source_ext = File.extname(source)[1..-1]
|
||||
if ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}"))))
|
||||
source += ".#{ext}"
|
||||
end
|
||||
|
||||
|
@ -30,7 +30,7 @@ module AtomFeedHelper
|
||||
# app/views/posts/index.atom.builder:
|
||||
# atom_feed do |feed|
|
||||
# feed.title("My great blog!")
|
||||
# feed.updated((@posts.first.created_at))
|
||||
# feed.updated(@posts.first.created_at)
|
||||
#
|
||||
# for post in @posts
|
||||
# feed.entry(post) do |entry|
|
||||
|
@ -971,7 +971,8 @@ def fields_for_with_nested_attributes(association_name, args, block)
|
||||
@template.fields_for(child_name, child, *args, &block)
|
||||
end.join
|
||||
else
|
||||
@template.fields_for(name, association, *args, &block)
|
||||
object = args.first.respond_to?(:new_record?) ? args.first : association
|
||||
@template.fields_for(name, object, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -507,7 +507,30 @@ def mail_to(email_address, name = nil, html_options = {})
|
||||
# current_page?(:controller => 'shop', :action => 'checkout')
|
||||
# # => true
|
||||
#
|
||||
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'asc)
|
||||
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'asc')
|
||||
# # => false
|
||||
#
|
||||
# current_page?(:action => 'checkout')
|
||||
# # => true
|
||||
#
|
||||
# current_page?(:controller => 'library', :action => 'checkout')
|
||||
# # => false
|
||||
#
|
||||
# Let's say we're in the <tt>/shop/checkout?order=desc&page=1</tt> action.
|
||||
#
|
||||
# current_page?(:action => 'process')
|
||||
# # => false
|
||||
#
|
||||
# current_page?(:controller => 'shop', :action => 'checkout')
|
||||
# # => true
|
||||
#
|
||||
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'1')
|
||||
# # => true
|
||||
#
|
||||
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'2')
|
||||
# # => false
|
||||
#
|
||||
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc')
|
||||
# # => false
|
||||
#
|
||||
# current_page?(:action => 'checkout')
|
||||
@ -516,7 +539,7 @@ def mail_to(email_address, name = nil, html_options = {})
|
||||
# current_page?(:controller => 'library', :action => 'checkout')
|
||||
# # => false
|
||||
def current_page?(options)
|
||||
url_string = CGI.escapeHTML(url_for(options))
|
||||
url_string = CGI.unescapeHTML(url_for(options))
|
||||
request = @controller.request
|
||||
# We ignore any extra parameters in the request_uri if the
|
||||
# submitted url doesn't have any either. This lets the function
|
||||
|
@ -2,7 +2,11 @@ module ActionView #:nodoc:
|
||||
class PathSet < Array #:nodoc:
|
||||
def self.type_cast(obj)
|
||||
if obj.is_a?(String)
|
||||
Template::EagerPath.new(obj)
|
||||
if !Object.const_defined?(:Rails) || Rails.configuration.cache_classes
|
||||
Template::EagerPath.new(obj)
|
||||
else
|
||||
Template::Path.new(obj)
|
||||
end
|
||||
else
|
||||
obj
|
||||
end
|
||||
|
@ -277,6 +277,9 @@ def render_explicit_html_template
|
||||
def render_implicit_html_template_from_xhr_request
|
||||
end
|
||||
|
||||
def render_implicit_js_template_without_layout
|
||||
end
|
||||
|
||||
def formatted_html_erb
|
||||
end
|
||||
|
||||
@ -681,7 +684,8 @@ def determine_layout
|
||||
"render_with_explicit_string_template",
|
||||
"render_js_with_explicit_template",
|
||||
"render_js_with_explicit_action_template",
|
||||
"delete_with_js", "update_page", "update_page_with_instance_variables"
|
||||
"delete_with_js", "update_page", "update_page_with_instance_variables",
|
||||
"render_implicit_js_template_without_layout"
|
||||
|
||||
"layouts/standard"
|
||||
when "action_talk_to_layout", "layout_overriding_layout"
|
||||
@ -1018,6 +1022,11 @@ def test_should_implicitly_render_html_template_from_xhr_request
|
||||
assert_equal "Hello HTML!", @response.body
|
||||
end
|
||||
|
||||
def test_should_implicitly_render_js_template_without_layout
|
||||
get :render_implicit_js_template_without_layout, :format => :js
|
||||
assert_no_match /<html>/, @response.body
|
||||
end
|
||||
|
||||
def test_should_render_formatted_template
|
||||
get :formatted_html_erb
|
||||
assert_equal 'formatted html erb', @response.body
|
||||
|
1
actionpack/test/fixtures/test/render_implicit_js_template_without_layout.js.erb
vendored
Normal file
@ -0,0 +1 @@
|
||||
alert('hello');
|
@ -586,6 +586,15 @@ def test_nested_fields_for_with_a_new_record_on_a_nested_attributes_one_to_one_a
|
||||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_nested_fields_for_with_explicitly_passed_object_on_a_nested_attributes_one_to_one_association
|
||||
form_for(:post, @post) do |f|
|
||||
f.fields_for(:author, Author.new(123)) do |af|
|
||||
assert_not_nil af.object
|
||||
assert_equal 123, af.object.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association
|
||||
@post.author = Author.new(321)
|
||||
|
||||
|
@ -252,6 +252,27 @@ def test_link_to_if
|
||||
assert_equal "Showing", link_to_if(false, "Showing", :action => "show", :controller => "weblog", :id => 1)
|
||||
end
|
||||
|
||||
def test_current_page_with_simple_url
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show")
|
||||
@controller.url = "http://www.example.com/weblog/show"
|
||||
assert current_page?({ :action => "show", :controller => "weblog" })
|
||||
assert current_page?("http://www.example.com/weblog/show")
|
||||
end
|
||||
|
||||
def test_current_page_ignoring_params
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert current_page?({ :action => "show", :controller => "weblog" })
|
||||
assert current_page?("http://www.example.com/weblog/show")
|
||||
end
|
||||
|
||||
def test_current_page_with_params_that_match
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert current_page?({ :action => "show", :controller => "weblog", :order => "desc", :page => "1" })
|
||||
assert current_page?("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
end
|
||||
|
||||
def test_link_unless_current
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show")
|
||||
@controller.url = "http://www.example.com/weblog/show"
|
||||
@ -263,11 +284,23 @@ def test_link_unless_current
|
||||
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show")
|
||||
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=1"
|
||||
assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog", :order=>'desc', :page=>'1' })
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
|
||||
assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1")
|
||||
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc")
|
||||
@controller.url = "http://www.example.com/weblog/show?order=asc"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=asc\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=asc")
|
||||
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1")
|
||||
@controller.url = "http://www.example.com/weblog/show?order=desc&page=2"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&page=2\">Showing</a>", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" })
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/show?order=desc&page=2\">Showing</a>", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=2")
|
||||
|
||||
|
||||
@controller.request = RequestMock.new("http://www.example.com/weblog/show")
|
||||
@controller.url = "http://www.example.com/weblog/list"
|
||||
assert_equal "<a href=\"http://www.example.com/weblog/list\">Listing</a>",
|
||||
@ -319,7 +352,7 @@ def test_mail_to_with_replace_options
|
||||
assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
|
||||
assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
|
||||
end
|
||||
|
||||
|
||||
def protect_against_forgery?
|
||||
false
|
||||
end
|
||||
|
@ -1,3 +1,8 @@
|
||||
*Edge*
|
||||
|
||||
* Added that ActiveRecord::Base.exists? can be called with no arguments #1817 [Scott Taylor]
|
||||
|
||||
|
||||
*2.3.0 [RC1] (February 1st, 2009)*
|
||||
|
||||
* Add Support for updating deeply nested models from a single form. #1202 [Eloy Duran]
|
||||
|
@ -1090,6 +1090,22 @@ def belongs_to(association_id, options = {})
|
||||
# but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
|
||||
# custom <tt>:join_table</tt> option if you need to.
|
||||
#
|
||||
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
||||
# join table with a migration such as this:
|
||||
#
|
||||
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
|
||||
# def self.up
|
||||
# create_table :developers_projects, :id => false do |t|
|
||||
# t.integer :developer_id
|
||||
# t.integer :project_id
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def self.down
|
||||
# drop_table :developers_projects
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
|
||||
# +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as
|
||||
# readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any
|
||||
|
@ -324,6 +324,7 @@ def query_attribute(attr_name)
|
||||
if Numeric === value || value !~ /[^0-9]/
|
||||
!value.to_i.zero?
|
||||
else
|
||||
return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
|
||||
!value.blank?
|
||||
end
|
||||
elsif column.number?
|
||||
|
@ -129,6 +129,7 @@ def self.included(base)
|
||||
base.class_eval do
|
||||
alias_method_chain :reload, :autosave_associations
|
||||
alias_method_chain :save, :autosave_associations
|
||||
alias_method_chain :save!, :autosave_associations
|
||||
alias_method_chain :valid?, :autosave_associations
|
||||
|
||||
%w{ has_one belongs_to has_many has_and_belongs_to_many }.each do |type|
|
||||
@ -161,6 +162,17 @@ def save_with_autosave_associations(perform_validation = true)
|
||||
end
|
||||
end
|
||||
|
||||
# Attempts to save the record just like save_with_autosave_associations but
|
||||
# will raise a RecordInvalid exception instead of returning false if the
|
||||
# record is not valid.
|
||||
def save_with_autosave_associations!
|
||||
if valid_with_autosave_associations?
|
||||
save_with_autosave_associations(false) || raise(RecordNotSaved)
|
||||
else
|
||||
raise RecordInvalid.new(self)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns whether or not the parent, <tt>self</tt>, and any loaded autosave associations are valid.
|
||||
def valid_with_autosave_associations?
|
||||
if valid_without_autosave_associations?
|
||||
|
@ -663,7 +663,7 @@ def find_by_sql(sql)
|
||||
|
||||
|
||||
# Returns true if a record exists in the table that matches the +id+ or
|
||||
# conditions given, or false otherwise. The argument can take four forms:
|
||||
# conditions given, or false otherwise. The argument can take five forms:
|
||||
#
|
||||
# * Integer - Finds the record with this primary key.
|
||||
# * String - Finds the record with a primary key corresponding to this
|
||||
@ -672,6 +672,7 @@ def find_by_sql(sql)
|
||||
# (such as <tt>['color = ?', 'red']</tt>).
|
||||
# * Hash - Finds the record that matches these +find+-style conditions
|
||||
# (such as <tt>{:color => 'red'}</tt>).
|
||||
# * No args - Returns false if the table is empty, true otherwise.
|
||||
#
|
||||
# For more information about specifying conditions as a Hash or Array,
|
||||
# see the Conditions section in the introduction to ActiveRecord::Base.
|
||||
@ -685,7 +686,8 @@ def find_by_sql(sql)
|
||||
# Person.exists?('5')
|
||||
# Person.exists?(:name => "David")
|
||||
# Person.exists?(['name LIKE ?', "%#{query}%"])
|
||||
def exists?(id_or_conditions)
|
||||
# Person.exists?
|
||||
def exists?(id_or_conditions = {})
|
||||
connection.select_all(
|
||||
construct_finder_sql(
|
||||
:select => "#{quoted_table_name}.#{primary_key}",
|
||||
@ -1990,12 +1992,16 @@ def all_attributes_exists?(attribute_names)
|
||||
attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) }
|
||||
end
|
||||
|
||||
def attribute_condition(argument)
|
||||
def attribute_condition(quoted_column_name, argument)
|
||||
case argument
|
||||
when nil then "IS ?"
|
||||
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "IN (?)"
|
||||
when Range then "BETWEEN ? AND ?"
|
||||
else "= ?"
|
||||
when nil then "#{quoted_column_name} IS ?"
|
||||
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "#{quoted_column_name} IN (?)"
|
||||
when Range then if argument.exclude_end?
|
||||
"#{quoted_column_name} >= ? AND #{quoted_column_name} < ?"
|
||||
else
|
||||
"#{quoted_column_name} BETWEEN ? AND ?"
|
||||
end
|
||||
else "#{quoted_column_name} = ?"
|
||||
end
|
||||
end
|
||||
|
||||
@ -2305,7 +2311,7 @@ def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name)
|
||||
table_name = connection.quote_table_name(table_name)
|
||||
end
|
||||
|
||||
"#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
|
||||
attribute_condition("#{table_name}.#{connection.quote_column_name(attr)}", value)
|
||||
else
|
||||
sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s))
|
||||
end
|
||||
|
@ -8,6 +8,7 @@ module ConnectionAdapters #:nodoc:
|
||||
# An abstract definition of a column in a table.
|
||||
class Column
|
||||
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
|
||||
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
|
||||
|
||||
module Format
|
||||
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
|
||||
|
@ -86,7 +86,8 @@ def self.included(base)
|
||||
# For each key in the hash that starts with the string 'new' a new model
|
||||
# will be instantiated. When the proc given with the <tt>:reject_if</tt>
|
||||
# option evaluates to +false+ for a certain attribute hash no record will
|
||||
# be built for that hash.
|
||||
# be built for that hash. (Rejecting new records can alternatively be done
|
||||
# by utilizing the <tt>'_delete'</tt> key. Scroll down for more info.)
|
||||
#
|
||||
# params = { 'member' => {
|
||||
# 'name' => 'joe', 'posts_attributes' => {
|
||||
@ -258,11 +259,14 @@ def should_destroy_nested_attributes_record?(allow_destroy, attributes)
|
||||
# If a <tt>:reject_if</tt> proc exists for this association, it will be
|
||||
# called with the attributes as its argument. If the proc returns a truthy
|
||||
# value, the record is _not_ build.
|
||||
#
|
||||
# Alternatively, you can specify the <tt>'_delete'</tt> key to _not_ build
|
||||
# a record. See should_destroy_nested_attributes_record? for more info.
|
||||
def build_new_nested_attributes_record(association_name, attributes)
|
||||
if reject_proc = self.class.reject_new_nested_attributes_procs[association_name]
|
||||
return if reject_proc.call(attributes)
|
||||
end
|
||||
send(association_name).build(attributes)
|
||||
send(association_name).build(attributes) unless should_destroy_nested_attributes_record?(true, attributes)
|
||||
end
|
||||
|
||||
# Assigns the attributes to the record specified by +id+. Or marks it for
|
||||
|
@ -99,7 +99,7 @@ def self.find_by_session_id(*args)
|
||||
define_method(:session_id=) { |session_id| self.sessid = session_id }
|
||||
else
|
||||
def self.find_by_session_id(session_id)
|
||||
find :first, :conditions => ["session_id #{attribute_condition(session_id)}", session_id]
|
||||
find :first, :conditions => {:session_id=>session_id}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -744,7 +744,7 @@ def validates_uniqueness_of(*attr_names)
|
||||
if scope = configuration[:scope]
|
||||
Array(scope).map do |scope_item|
|
||||
scope_value = record.send(scope_item)
|
||||
condition_sql << " AND #{record.class.quoted_table_name}.#{scope_item} #{attribute_condition(scope_value)}"
|
||||
condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value)
|
||||
condition_params << scope_value
|
||||
end
|
||||
end
|
||||
|
@ -56,6 +56,18 @@ def test_should_unserialize_attributes_for_frozen_records
|
||||
assert_equal myobj, topic.content
|
||||
end
|
||||
|
||||
def test_typecast_attribute_from_select_to_false
|
||||
topic = Topic.create(:title => 'Budget')
|
||||
topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
|
||||
assert !topic.is_test?
|
||||
end
|
||||
|
||||
def test_typecast_attribute_from_select_to_true
|
||||
topic = Topic.create(:title => 'Budget')
|
||||
topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
|
||||
assert topic.is_test?
|
||||
end
|
||||
|
||||
def test_kernel_methods_not_implemented_in_activerecord
|
||||
%w(test name display y).each do |method|
|
||||
assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
|
||||
|
@ -169,6 +169,12 @@ def test_should_automatically_save_the_associated_model
|
||||
assert_equal 'The Vile Insanity', @pirate.reload.ship.name
|
||||
end
|
||||
|
||||
def test_should_automatically_save_bang_the_associated_model
|
||||
@pirate.ship.name = 'The Vile Insanity'
|
||||
@pirate.save!
|
||||
assert_equal 'The Vile Insanity', @pirate.reload.ship.name
|
||||
end
|
||||
|
||||
def test_should_automatically_validate_the_associated_model
|
||||
@pirate.ship.name = ''
|
||||
assert !@pirate.valid?
|
||||
@ -245,6 +251,12 @@ def test_should_automatically_save_the_associated_model
|
||||
assert_equal 'Arr', @ship.reload.pirate.catchphrase
|
||||
end
|
||||
|
||||
def test_should_automatically_save_bang_the_associated_model
|
||||
@ship.pirate.catchphrase = 'Arr'
|
||||
@ship.save!
|
||||
assert_equal 'Arr', @ship.reload.pirate.catchphrase
|
||||
end
|
||||
|
||||
def test_should_automatically_validate_the_associated_model
|
||||
@ship.pirate.catchphrase = ''
|
||||
assert !@ship.valid?
|
||||
@ -298,6 +310,14 @@ def test_should_automatically_save_the_associated_models
|
||||
assert_equal new_names, @pirate.reload.send(@association_name).map(&:name)
|
||||
end
|
||||
|
||||
def test_should_automatically_save_bang_the_associated_models
|
||||
new_names = ['Grace OMalley', 'Privateers Greed']
|
||||
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
|
||||
|
||||
@pirate.save!
|
||||
assert_equal new_names, @pirate.reload.send(@association_name).map(&:name)
|
||||
end
|
||||
|
||||
def test_should_automatically_validate_the_associated_models
|
||||
@pirate.send(@association_name).each { |child| child.name = '' }
|
||||
|
||||
@ -347,7 +367,9 @@ def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_t
|
||||
def test_should_not_load_the_associated_models_if_they_were_not_loaded_yet
|
||||
assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! }
|
||||
|
||||
assert_queries(2) do
|
||||
@pirate.send(@association_name).class # hack to load the target
|
||||
|
||||
assert_queries(3) do
|
||||
@pirate.catchphrase = 'Yarr'
|
||||
new_names = ['Grace OMalley', 'Privateers Greed']
|
||||
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
|
||||
|
@ -26,6 +26,7 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.execute("set lc_monetary = 'C'")
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_arrays (commission_by_quarter, nicknames) VALUES ( '{35000,21000,18000,17000}', '{foo,bar,baz}' )")
|
||||
@first_array = PostgresqlArray.find(1)
|
||||
|
@ -94,7 +94,16 @@ def test_exists
|
||||
|
||||
assert_raise(NoMethodError) { Topic.exists?([1,2]) }
|
||||
end
|
||||
|
||||
|
||||
def test_exists_returns_true_with_one_record_and_no_args
|
||||
assert Topic.exists?
|
||||
end
|
||||
|
||||
def test_does_not_exist_with_empty_table_and_no_args_given
|
||||
Topic.delete_all
|
||||
assert !Topic.exists?
|
||||
end
|
||||
|
||||
def test_exists_with_aggregate_having_three_mappings
|
||||
existing_address = customers(:david).address
|
||||
assert Customer.exists?(:address => existing_address)
|
||||
@ -298,6 +307,12 @@ def test_find_on_hash_conditions_with_range
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
|
||||
end
|
||||
|
||||
def test_find_on_hash_conditions_with_end_exclusive_range
|
||||
assert_equal [1,2,3], Topic.find(:all, :conditions => { :id => 1..3 }).map(&:id).sort
|
||||
assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1...3 }).map(&:id).sort
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) }
|
||||
end
|
||||
|
||||
def test_find_on_hash_conditions_with_multiple_ranges
|
||||
assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
|
||||
assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
|
||||
|
@ -233,6 +233,20 @@ def test_should_automatically_build_new_associated_models_for_each_entry_in_a_ha
|
||||
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
||||
end
|
||||
|
||||
def test_should_remove_delete_key_from_arguments_hash_of_new_records
|
||||
assert_nothing_raised ActiveRecord::UnknownAttributeError do
|
||||
@pirate.send(association_setter, { 'new_1' => { '_delete' => '0' }})
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_ignore_new_associated_records_with_truthy_delete_attribute
|
||||
@pirate.send(@association_name).destroy_all
|
||||
@pirate.reload.attributes = { association_getter => { 'new_1' => { :name => 'Grace OMalley' }, 'new_2' => { :name => 'Privateers Greed', '_delete' => '1' }}}
|
||||
|
||||
assert_equal 1, @pirate.send(@association_name).length
|
||||
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
||||
end
|
||||
|
||||
def test_should_sort_the_hash_by_the_keys_before_building_new_associated_models
|
||||
attributes = ActiveSupport::OrderedHash.new
|
||||
attributes['new_123726353'] = { :name => 'Grace OMalley' }
|
||||
|
@ -284,7 +284,7 @@ def transliterate(string)
|
||||
|
||||
# The iconv transliteration code doesn't function correctly
|
||||
# on some platforms, but it's very fast where it does function.
|
||||
elsif "foo" != Inflector.transliterate("föö")
|
||||
elsif "foo" != (Inflector.transliterate("föö") rescue nil)
|
||||
undef_method :transliterate
|
||||
def transliterate(string)
|
||||
string.mb_chars.normalize(:kd). # Decompose accented characters
|
||||
|
@ -244,6 +244,11 @@ def copy_with_rewritten_ruby_path(src_file, dest_file)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"'
|
||||
task :guides do
|
||||
ruby "guides/rails_guides.rb"
|
||||
end
|
||||
|
||||
|
||||
# Generate documentation ------------------------------------------------------------------
|
||||
|
||||
|
188
railties/guides/files/javascripts/code_highlighter.js
Executable file
@ -0,0 +1,188 @@
|
||||
/* Unobtrustive Code Highlighter By Dan Webb 11/2005
|
||||
Version: 0.4
|
||||
|
||||
Usage:
|
||||
Add a script tag for this script and any stylesets you need to use
|
||||
to the page in question, add correct class names to CODE elements,
|
||||
define CSS styles for elements. That's it!
|
||||
|
||||
Known to work on:
|
||||
IE 5.5+ PC
|
||||
Firefox/Mozilla PC/Mac
|
||||
Opera 7.23 + PC
|
||||
Safari 2
|
||||
|
||||
Known to degrade gracefully on:
|
||||
IE5.0 PC
|
||||
|
||||
Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
|
||||
in older browsers use expressions that use lookahead in string format when defining stylesets.
|
||||
|
||||
This script is inspired by star-light by entirely cunning Dean Edwards
|
||||
http://dean.edwards.name/star-light/.
|
||||
*/
|
||||
|
||||
// replace callback support for safari.
|
||||
if ("a".replace(/a/, function() {return "b"}) != "b") (function(){
|
||||
var default_replace = String.prototype.replace;
|
||||
String.prototype.replace = function(search,replace){
|
||||
// replace is not function
|
||||
if(typeof replace != "function"){
|
||||
return default_replace.apply(this,arguments)
|
||||
}
|
||||
var str = "" + this;
|
||||
var callback = replace;
|
||||
// search string is not RegExp
|
||||
if(!(search instanceof RegExp)){
|
||||
var idx = str.indexOf(search);
|
||||
return (
|
||||
idx == -1 ? str :
|
||||
default_replace.apply(str,[search,callback(search, idx, str)])
|
||||
)
|
||||
}
|
||||
var reg = search;
|
||||
var result = [];
|
||||
var lastidx = reg.lastIndex;
|
||||
var re;
|
||||
while((re = reg.exec(str)) != null){
|
||||
var idx = re.index;
|
||||
var args = re.concat(idx, str);
|
||||
result.push(
|
||||
str.slice(lastidx,idx),
|
||||
callback.apply(null,args).toString()
|
||||
);
|
||||
if(!reg.global){
|
||||
lastidx += RegExp.lastMatch.length;
|
||||
break
|
||||
}else{
|
||||
lastidx = reg.lastIndex;
|
||||
}
|
||||
}
|
||||
result.push(str.slice(lastidx));
|
||||
return result.join("")
|
||||
}
|
||||
})();
|
||||
|
||||
var CodeHighlighter = { styleSets : new Array };
|
||||
|
||||
CodeHighlighter.addStyle = function(name, rules) {
|
||||
// using push test to disallow older browsers from adding styleSets
|
||||
if ([].push) this.styleSets.push({
|
||||
name : name,
|
||||
rules : rules,
|
||||
ignoreCase : arguments[2] || false
|
||||
})
|
||||
|
||||
function setEvent() {
|
||||
// set highlighter to run on load (use LowPro if present)
|
||||
if (typeof Event != 'undefined' && typeof Event.onReady == 'function')
|
||||
return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
|
||||
|
||||
var old = window.onload;
|
||||
|
||||
if (typeof window.onload != 'function') {
|
||||
window.onload = function() { CodeHighlighter.init() };
|
||||
} else {
|
||||
window.onload = function() {
|
||||
old();
|
||||
CodeHighlighter.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only set the event when the first style is added
|
||||
if (this.styleSets.length==1) setEvent();
|
||||
}
|
||||
|
||||
CodeHighlighter.init = function() {
|
||||
if (!document.getElementsByTagName) return;
|
||||
if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function
|
||||
// throw out older browsers
|
||||
|
||||
var codeEls = document.getElementsByTagName("CODE");
|
||||
// collect array of all pre elements
|
||||
codeEls.filter = function(f) {
|
||||
var a = new Array;
|
||||
for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
var rules = new Array;
|
||||
rules.toString = function() {
|
||||
// joins regexes into one big parallel regex
|
||||
var exps = new Array;
|
||||
for (var i = 0; i < this.length; i++) exps.push(this[i].exp);
|
||||
return exps.join("|");
|
||||
}
|
||||
|
||||
function addRule(className, rule) {
|
||||
// add a replace rule
|
||||
var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
|
||||
// converts regex rules to strings and chops of the slashes
|
||||
rules.push({
|
||||
className : className,
|
||||
exp : "(" + exp + ")",
|
||||
length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule
|
||||
replacement : rule.replacement || null
|
||||
});
|
||||
}
|
||||
|
||||
function parse(text, ignoreCase) {
|
||||
// main text parsing and replacement
|
||||
return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() {
|
||||
var i = 0, j = 1, rule;
|
||||
while (rule = rules[i++]) {
|
||||
if (arguments[j]) {
|
||||
// if no custom replacement defined do the simple replacement
|
||||
if (!rule.replacement) return "<span class=\"" + rule.className + "\">" + arguments[0] + "</span>";
|
||||
else {
|
||||
// replace $0 with the className then do normal replaces
|
||||
var str = rule.replacement.replace("$0", rule.className);
|
||||
for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]);
|
||||
return str;
|
||||
}
|
||||
} else j+= rule.length;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function highlightCode(styleSet) {
|
||||
// clear rules array
|
||||
var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)");
|
||||
rules.length = 0;
|
||||
|
||||
// get stylable elements by filtering out all code elements without the correct className
|
||||
var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) });
|
||||
|
||||
// add style rules to parser
|
||||
for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
|
||||
|
||||
|
||||
// replace for all elements
|
||||
for (var i = 0; i < stylableEls.length; i++) {
|
||||
// EVIL hack to fix IE whitespace badness if it's inside a <pre>
|
||||
if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
|
||||
stylableEls[i] = stylableEls[i].parentNode;
|
||||
|
||||
parsed = stylableEls[i].innerHTML.replace(/(<code[^>]*>)([^<]*)<\/code>/i, function() {
|
||||
return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + "</code>"
|
||||
});
|
||||
parsed = parsed.replace(/\n( *)/g, function() {
|
||||
var spaces = "";
|
||||
for (var i = 0; i < arguments[1].length; i++) spaces+= " ";
|
||||
return "\n" + spaces;
|
||||
});
|
||||
parsed = parsed.replace(/\t/g, " ");
|
||||
parsed = parsed.replace(/\n(<\/\w+>)?/g, "<br />$1").replace(/<br \/>[\n\r\s]*<br \/>/g, "<p><br></p>");
|
||||
|
||||
} else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
|
||||
|
||||
stylableEls[i].innerHTML = parsed;
|
||||
}
|
||||
}
|
||||
|
||||
// run highlighter on all stylesets
|
||||
for (var i=0; i < this.styleSets.length; i++) {
|
||||
highlightCode(this.styleSets[i]);
|
||||
}
|
||||
}
|
8
railties/guides/files/javascripts/guides.js
Executable file
@ -0,0 +1,8 @@
|
||||
function guideMenu(){
|
||||
|
||||
if (document.getElementById('guides').style.display == "none") {
|
||||
document.getElementById('guides').style.display = "block";
|
||||
} else {
|
||||
document.getElementById('guides').style.display = "none";
|
||||
}
|
||||
}
|
90
railties/guides/files/javascripts/highlighters.js
Normal file
@ -0,0 +1,90 @@
|
||||
CodeHighlighter.addStyle("css", {
|
||||
comment : {
|
||||
exp : /\/\*[^*]*\*+([^\/][^*]*\*+)*\//
|
||||
},
|
||||
keywords : {
|
||||
exp : /@\w[\w\s]*/
|
||||
},
|
||||
selectors : {
|
||||
exp : "([\\w-:\\[.#][^{};>]*)(?={)"
|
||||
},
|
||||
properties : {
|
||||
exp : "([\\w-]+)(?=\\s*:)"
|
||||
},
|
||||
units : {
|
||||
exp : /([0-9])(em|en|px|%|pt)\b/,
|
||||
replacement : "$1<span class=\"$0\">$2</span>"
|
||||
},
|
||||
urls : {
|
||||
exp : /url\([^\)]*\)/
|
||||
}
|
||||
});
|
||||
|
||||
CodeHighlighter.addStyle("ruby",{
|
||||
comment : {
|
||||
exp : /#[^\n]+/
|
||||
},
|
||||
brackets : {
|
||||
exp : /\(|\)/
|
||||
},
|
||||
string : {
|
||||
exp : /'[^']*'|"[^"]*"/
|
||||
},
|
||||
keywords : {
|
||||
exp : /\b(do|end|self|class|def|if|module|yield|then|else|for|until|unless|while|elsif|case|when|break|retry|redo|rescue|require|raise)\b/
|
||||
},
|
||||
/* Added by Shelly Fisher (shelly@agileevolved.com) */
|
||||
symbol : {
|
||||
exp : /([^:])(:[A-Za-z0-9_!?]+)/
|
||||
},
|
||||
ivar : {
|
||||
exp : /\@[A-Za-z0-9_!?]+/
|
||||
}
|
||||
});
|
||||
|
||||
CodeHighlighter.addStyle("html", {
|
||||
comment : {
|
||||
exp: /<!\s*(--([^-]|[\r\n]|-[^-])*--\s*)>/
|
||||
},
|
||||
tag : {
|
||||
exp: /(<\/?)([a-zA-Z1-9]+\s?)/,
|
||||
replacement: "$1<span class=\"$0\">$2</span>"
|
||||
},
|
||||
string : {
|
||||
exp : /'[^']*'|"[^"]*"/
|
||||
},
|
||||
attribute : {
|
||||
exp: /\b([a-zA-Z-:]+)(=)/,
|
||||
replacement: "<span class=\"$0\">$1</span>$2"
|
||||
},
|
||||
doctype : {
|
||||
exp: /<!DOCTYPE([^&]|&[^g]|&g[^t])*>/
|
||||
}
|
||||
});
|
||||
|
||||
CodeHighlighter.addStyle("javascript",{
|
||||
comment : {
|
||||
exp : /(\/\/[^\n]*(\n|$))|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
|
||||
},
|
||||
brackets : {
|
||||
exp : /\(|\)/
|
||||
},
|
||||
string : {
|
||||
exp : /'[^']*'|"[^"]*"/
|
||||
},
|
||||
keywords : {
|
||||
exp : /\b(arguments|break|case|continue|default|delete|do|else|false|for|function|if|in|instanceof|new|null|return|switch|this|true|typeof|var|void|while|with)\b/
|
||||
},
|
||||
global : {
|
||||
exp : /\b(toString|valueOf|window|element|prototype|constructor|document|escape|unescape|parseInt|parseFloat|setTimeout|clearTimeout|setInterval|clearInterval|NaN|isNaN|Infinity)\b/
|
||||
}
|
||||
});
|
||||
|
||||
CodeHighlighter.addStyle("yaml", {
|
||||
keyword : {
|
||||
exp : /\/\*[^*]*\*+([^\/][^*]*\*+)*\//
|
||||
},
|
||||
value : {
|
||||
exp : /@\w[\w\s]*/
|
||||
},
|
||||
});
|
436
railties/guides/files/stylesheets/main.css
Normal file
@ -0,0 +1,436 @@
|
||||
/* Guides.rubyonrails.org */
|
||||
/* Main.css */
|
||||
/* Created January 30, 2009 */
|
||||
/* Modified January 31, 2009
|
||||
--------------------------------------- */
|
||||
|
||||
/* General
|
||||
--------------------------------------- */
|
||||
|
||||
.left {float: left; margin-right: 1em;}
|
||||
.right {float: right; margin-left: 1em;}
|
||||
.small {font-size: smaller;}
|
||||
.large {font-size: larger;}
|
||||
.hide {display: none;}
|
||||
|
||||
li ul, li ol { margin:0 1.5em; }
|
||||
ul, ol { margin: 0 1.5em 1.5em 1.5em; }
|
||||
|
||||
ul { list-style-type: disc; }
|
||||
ol { list-style-type: decimal; }
|
||||
|
||||
dl { margin: 0 0 1.5em 0; }
|
||||
dl dt { font-weight: bold; }
|
||||
dd { margin-left: 1.5em;}
|
||||
|
||||
pre,code { margin: 1.5em 0; white-space: pre; }
|
||||
pre,code,tt { font: 1em 'andale mono', 'lucida console', monospace; line-height: 1.5; }
|
||||
|
||||
abbr, acronym { border-bottom: 1px dotted #666; }
|
||||
address { margin: 0 0 1.5em; font-style: italic; }
|
||||
del { color:#666; }
|
||||
|
||||
blockquote { margin: 1.5em; color: #666; font-style: italic; }
|
||||
strong { font-weight: bold; }
|
||||
em, dfn { font-style: italic; }
|
||||
dfn { font-weight: bold; }
|
||||
sup, sub { line-height: 0; }
|
||||
p {margin: 0 0 1.5em;}
|
||||
|
||||
label { font-weight: bold; }
|
||||
fieldset { padding:1.4em; margin: 0 0 1.5em 0; border: 1px solid #ccc; }
|
||||
legend { font-weight: bold; font-size:1.2em; }
|
||||
|
||||
input.text, input.title,
|
||||
textarea, select {
|
||||
margin:0.5em 0;
|
||||
border:1px solid #bbb;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 1em 0;
|
||||
border: 1px solid #ddd;
|
||||
background: #f4f4f4;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table th, table td {
|
||||
padding: 0.25em;
|
||||
border-right: 1px dotted #e0e0e0;
|
||||
border-bottom: 1px dotted #e0e0e0;
|
||||
}
|
||||
|
||||
table th:last-child, table td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
table th {
|
||||
border-bottom: 1px solid #ddd;
|
||||
background: #f0f0f0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table td {
|
||||
}
|
||||
|
||||
table tt {
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
|
||||
/* Structure and Layout
|
||||
--------------------------------------- */
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 87.5%;
|
||||
line-height: 1.5em;
|
||||
background: #222;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
text-align: left;
|
||||
margin: 0 auto;
|
||||
width: 69em;
|
||||
}
|
||||
|
||||
#topNav {
|
||||
padding: 1em 0;
|
||||
color: #565656;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #c52f24 url(../../images/header_tile.gif) repeat-x;
|
||||
color: #FFF;
|
||||
padding: 1.5em 0;
|
||||
position: relative;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#feature {
|
||||
background: #d5e9f6 url(../../images/feature_tile.gif) repeat-x;
|
||||
color: #333;
|
||||
padding: 0.5em 0 1.5em;
|
||||
}
|
||||
|
||||
#container {
|
||||
background: #FFF;
|
||||
color: #333;
|
||||
padding: 0.5em 0 1.5em 0;
|
||||
}
|
||||
|
||||
#mainCol {
|
||||
width: 45em;
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
#subCol {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background: #FFF;
|
||||
padding: 1em 1.5em 1em 1.25em;
|
||||
width: 17em;
|
||||
font-size: 0.9285em;
|
||||
line-height: 1.3846em;
|
||||
}
|
||||
|
||||
#extraCol {display: none;}
|
||||
|
||||
#footer {
|
||||
padding: 2em 0;
|
||||
background: url(../../images/footer_tile.gif) repeat-x;
|
||||
}
|
||||
#footer .wrapper {
|
||||
padding-left: 2em;
|
||||
width: 67em;
|
||||
}
|
||||
|
||||
#header .wrapper, #topNav .wrapper, #feature .wrapper {padding-left: 1em; width: 68em;}
|
||||
#feature .wrapper {width: 45em; padding-right: 23em; position: relative; z-index: 0;}
|
||||
|
||||
/* Links
|
||||
--------------------------------------- */
|
||||
|
||||
a, a:link, a:visited {
|
||||
color: #ee3f3f;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#mainCol a, #subCol a {color: #980905;}
|
||||
|
||||
|
||||
/* Navigation
|
||||
--------------------------------------- */
|
||||
|
||||
.nav {margin: 0; padding: 0;}
|
||||
.nav li {display: inline; list-style: none;}
|
||||
|
||||
#header .nav {
|
||||
float: right;
|
||||
margin-top: 1.5em;
|
||||
font-size: 1.2857em;
|
||||
}
|
||||
|
||||
#header .nav li {margin: 0 0 0 0.5em;}
|
||||
#header .nav a {color: #FFF; text-decoration: none;}
|
||||
#header .nav a:hover {text-decoration: underline;}
|
||||
|
||||
#header .nav .index {
|
||||
padding: 0.5em 1.5em;
|
||||
border-radius: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
-moz-border-radius: 1em;
|
||||
background: #980905;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#header .nav .index a {
|
||||
background: #980905 url(../../images/nav_arrow.gif) no-repeat right top;
|
||||
padding-right: 1em;
|
||||
position: relative;
|
||||
z-index: 15;
|
||||
padding-bottom: 0.125em;
|
||||
}
|
||||
#header .nav .index:hover a, #header .nav .index a:hover {background-position: right -81px;}
|
||||
|
||||
#guides {
|
||||
width: 27em;
|
||||
display: block;
|
||||
background: #980905;
|
||||
border-radius: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
-moz-border-radius: 1em;
|
||||
-webkit-box-shadow: 0.25em 0.25em 1em rgba(0,0,0,0.25);
|
||||
-moz-box-shadow: rgba(0,0,0,0.25) 0.25em 0.25em 1em;
|
||||
color: #f1938c;
|
||||
padding: 1.5em 2em;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: -0.25em;
|
||||
right: 0;
|
||||
padding-top: 2em;
|
||||
}
|
||||
|
||||
#guides dt, #guides dd {
|
||||
font-weight: normal;
|
||||
font-size: 0.722em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#guides dt {padding:0; margin: 0.5em 0 0;}
|
||||
#guides a {color: #FFF; background: none !important;}
|
||||
#guides .L, #guides .R {float: left; width: 50%; margin: 0; padding: 0;}
|
||||
#guides .R {float: right;}
|
||||
#guides hr {
|
||||
display: block;
|
||||
border: none;
|
||||
height: 1px;
|
||||
color: #f1938c;
|
||||
background: #f1938c;
|
||||
}
|
||||
|
||||
/* Headings
|
||||
--------------------------------------- */
|
||||
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
line-height: 1em;
|
||||
margin: 0.6em 0 .2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.1428em;
|
||||
line-height: 1em;
|
||||
margin: 0.7em 0 .2333em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.7142em;
|
||||
line-height: 1.286em;
|
||||
margin: 0.875em 0 0.2916em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2857em;
|
||||
line-height: 1.2em;
|
||||
margin: 1.6667em 0 .3887em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
line-height: 1.5em;
|
||||
margin: 1em 0 .5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
line-height: 1.5em;
|
||||
margin: 1em 0 .5em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Content
|
||||
--------------------------------------- */
|
||||
|
||||
.pic {
|
||||
margin: 0 2em 2em 0;
|
||||
}
|
||||
|
||||
#topNav strong {color: #999; margin-right: 0.5em;}
|
||||
#topNav strong a {color: #FFF;}
|
||||
|
||||
#header h1 {
|
||||
float: left;
|
||||
background: url(../../images/ruby_guides_logo.gif) no-repeat;
|
||||
width: 492px;
|
||||
text-indent: -9999em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header h1 a {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
height: 77px;
|
||||
}
|
||||
|
||||
#feature p {
|
||||
font-size: 1.2857em;
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
#feature ul {margin-left: 0;}
|
||||
#feature ul li {
|
||||
list-style: none;
|
||||
background: url(../../images/check_bullet.gif) no-repeat left 0.5em;
|
||||
padding: 0.5em 1.75em 0.5em 1.75em;
|
||||
font-size: 1.1428em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#mainCol dd, #subCol dd {
|
||||
padding: 0.25em 0 1em;
|
||||
border-bottom: 1px solid #CCC;
|
||||
margin-bottom: 1em;
|
||||
margin-left: 0;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
#mainCol dt, #subCol dt {
|
||||
font-size: 1.2857em;
|
||||
padding: 0.125em 0 0.25em 28px;
|
||||
margin-bottom: 0;
|
||||
background: url(../../images/book_icon.gif) no-repeat left top;
|
||||
}
|
||||
|
||||
#mainCol dd.ticket, #subCol dd.ticket {
|
||||
background: #fff9d8 url(../../images/tab_yellow.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 1.25em 1em 1.25em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
#mainCol dd.warning, #subCol dd.warning {
|
||||
background: #f9d9d8 url(../../images/tab_red.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 1.25em 1.25em 1.25em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
#subCol .chapters {color: #980905;}
|
||||
#subCol .chapters a {font-weight: bold;}
|
||||
#subCol .chapters ul a {font-weight: normal;}
|
||||
#subCol .chapters li {margin-bottom: 0.75em;}
|
||||
#subCol h3.chapter {margin-top: 0.25em;}
|
||||
#subCol h3.chapter img {vertical-align: text-bottom;}
|
||||
#subCol .chapters ul {margin-left: 0; margin-top: 0.5em;}
|
||||
#subCol .chapters ul li {
|
||||
list-style: none;
|
||||
padding: 0 0 0 1em;
|
||||
background: url(../../images/bullet.gif) no-repeat left 0.45em;
|
||||
margin-left: 0;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
tt {
|
||||
background: #EEE;
|
||||
border: 1px solid #CCC;
|
||||
padding: 0.25em 0.5em;
|
||||
font-family: monaco, "Bitstream Vera Sans Mono", "Courier New", courier, monospace;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: monaco, "Bitstream Vera Sans Mono", "Courier New", courier, monospace;
|
||||
background: #EEE url(../../images/tab_grey.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 0.25em 1em 0.5em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.note {
|
||||
background: #fff9d8 url(../../images/tab_note.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 1em 1em 0.25em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #d5e9f6 url(../../images/tab_info.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 1em 1em 0.25em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background: #f9d9d8 url(../../images/tab_red.gif) no-repeat left top;
|
||||
border: none;
|
||||
padding: 1em 1em 0.25em 48px;
|
||||
margin-left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.warning tt, .note tt, .info tt {border:none; background: none; padding: 0;}
|
||||
|
||||
em.highlight {
|
||||
background: #fffcdb;
|
||||
padding: 0 0.25em;
|
||||
}
|
||||
|
||||
#mainCol ul li {
|
||||
list-style:none;
|
||||
background: url(../../images/grey_bullet.gif) no-repeat left 0.5em;
|
||||
padding-left: 1em;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Clearing
|
||||
--------------------------------------- */
|
||||
|
||||
.clearfix:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.clearfix {display: inline-block;}
|
||||
* html .clearfix {height: 1%;}
|
||||
.clearfix {display: block;}
|
||||
.clear { clear:both; }
|
52
railties/guides/files/stylesheets/print.css
Executable file
@ -0,0 +1,52 @@
|
||||
/* Guides.rubyonrails.org */
|
||||
/* Print.css */
|
||||
/* Created January 30, 2009 */
|
||||
/* Modified January 31, 2009
|
||||
--------------------------------------- */
|
||||
|
||||
body, .wrapper, .note, .info, code, #topNav, .L, .R, #frame, #container, #header, #navigation, #footer, #feature, #mainCol, #subCol, #extraCol, .content {position: static; text-align: left; text-indent: 0; background: White; color: Black; border-color: Black; width: auto; height: auto; display: block; float: none; min-height: 0; margin: 0; padding: 0;}
|
||||
|
||||
body {
|
||||
background: #FFF;
|
||||
font-size: 10pt !important;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
color: #000;
|
||||
padding: 0 3%;
|
||||
}
|
||||
|
||||
.hide, .nav {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
background: transparent;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr {
|
||||
background:#ccc;
|
||||
color:#ccc;
|
||||
width:100%;
|
||||
height:2px;
|
||||
margin:2em 0;
|
||||
padding:0;
|
||||
border:none;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 { font-family: "Helvetica Neue", Arial, "Lucida Grande", sans-serif; }
|
||||
code { font:.9em "Courier New", Monaco, Courier, monospace; }
|
||||
|
||||
img { float:left; margin:1.5em 1.5em 1.5em 0; }
|
||||
a img { border:none; }
|
||||
|
||||
blockquote {
|
||||
margin:1.5em;
|
||||
padding:1em;
|
||||
font-style:italic;
|
||||
font-size:.9em;
|
||||
}
|
||||
|
||||
.small { font-size: .9em; }
|
||||
.large { font-size: 1.1em; }
|
43
railties/guides/files/stylesheets/reset.css
Executable file
@ -0,0 +1,43 @@
|
||||
/* Guides.rubyonrails.org */
|
||||
/* Reset.css */
|
||||
/* Created January 30, 2009
|
||||
--------------------------------------- */
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-size: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body {line-height: 1; color: black; background: white;}
|
||||
a img {border:none;}
|
||||
ins {text-decoration: none;}
|
||||
del {text-decoration: line-through;}
|
||||
|
||||
:focus {
|
||||
-moz-outline:0;
|
||||
outline:0;
|
||||
outline-offset:0;
|
||||
}
|
||||
|
||||
/* tables still need 'cellspacing="0"' in the markup */
|
||||
table {border-collapse: collapse; border-spacing: 0;}
|
||||
caption, th, td {text-align: left; font-weight: normal;}
|
||||
|
||||
blockquote, q {quotes: none;}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
13
railties/guides/files/stylesheets/style.css
Executable file
@ -0,0 +1,13 @@
|
||||
/* Guides.rubyonrails.org */
|
||||
/* Style.css */
|
||||
/* Created January 30, 2009
|
||||
--------------------------------------- */
|
||||
|
||||
/*
|
||||
---------------------------------------
|
||||
Import advanced style sheet
|
||||
---------------------------------------
|
||||
*/
|
||||
|
||||
@import url("reset.css");
|
||||
@import url("main.css");
|
31
railties/guides/files/stylesheets/syntax.css
Normal file
@ -0,0 +1,31 @@
|
||||
.html .tag {
|
||||
color : green;
|
||||
}
|
||||
|
||||
.html .doctype {
|
||||
color: #708090;
|
||||
}
|
||||
|
||||
.erb .tag {
|
||||
color : green;
|
||||
}
|
||||
|
||||
.erb .doctype {
|
||||
color: #708090;
|
||||
}
|
||||
|
||||
.ruby .keywords {
|
||||
color : red;
|
||||
}
|
||||
|
||||
.ruby .ivar {
|
||||
color : blue;
|
||||
}
|
||||
|
||||
.ruby .comment {
|
||||
color: #708090;
|
||||
}
|
||||
|
||||
.ruby .symbol {
|
||||
color: green;
|
||||
}
|
BIN
railties/guides/images/belongs_to.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
railties/guides/images/book_icon.gif
Normal file
After Width: | Height: | Size: 337 B |
BIN
railties/guides/images/bullet.gif
Normal file
After Width: | Height: | Size: 60 B |
BIN
railties/guides/images/chapters_icon.gif
Normal file
After Width: | Height: | Size: 628 B |
BIN
railties/guides/images/check_bullet.gif
Normal file
After Width: | Height: | Size: 384 B |
BIN
railties/guides/images/credits_pic_blank.gif
Normal file
After Width: | Height: | Size: 613 B |
BIN
railties/guides/images/csrf.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
railties/guides/images/customized_error_messages.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
railties/guides/images/error_messages.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
railties/guides/images/feature_tile.gif
Normal file
After Width: | Height: | Size: 43 B |
BIN
railties/guides/images/footer_tile.gif
Normal file
After Width: | Height: | Size: 44 B |
BIN
railties/guides/images/grey_bullet.gif
Normal file
After Width: | Height: | Size: 45 B |
BIN
railties/guides/images/habtm.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
railties/guides/images/has_many.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
railties/guides/images/has_many_through.png
Normal file
After Width: | Height: | Size: 98 KiB |
BIN
railties/guides/images/has_one.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
railties/guides/images/has_one_through.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
railties/guides/images/header_backdrop.png
Normal file
After Width: | Height: | Size: 882 B |
BIN
railties/guides/images/header_tile.gif
Normal file
After Width: | Height: | Size: 44 B |
BIN
railties/guides/images/i18n/demo_localized_pirate.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
railties/guides/images/i18n/demo_translated_en.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
railties/guides/images/i18n/demo_translated_pirate.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
railties/guides/images/i18n/demo_translation_missing.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
railties/guides/images/i18n/demo_untranslated.png
Normal file
After Width: | Height: | Size: 32 KiB |
5
railties/guides/images/icons/README
Normal file
@ -0,0 +1,5 @@
|
||||
Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook
|
||||
icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency
|
||||
from the Jimmac icons to get round MS IE and FOP PNG incompatibilies.
|
||||
|
||||
Stuart Rackham
|
BIN
railties/guides/images/icons/callouts/1.png
Normal file
After Width: | Height: | Size: 329 B |
BIN
railties/guides/images/icons/callouts/10.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
railties/guides/images/icons/callouts/11.png
Normal file
After Width: | Height: | Size: 565 B |
BIN
railties/guides/images/icons/callouts/12.png
Normal file
After Width: | Height: | Size: 617 B |
BIN
railties/guides/images/icons/callouts/13.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
railties/guides/images/icons/callouts/14.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
railties/guides/images/icons/callouts/15.png
Normal file
After Width: | Height: | Size: 640 B |
BIN
railties/guides/images/icons/callouts/2.png
Normal file
After Width: | Height: | Size: 353 B |
BIN
railties/guides/images/icons/callouts/3.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
railties/guides/images/icons/callouts/4.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
railties/guides/images/icons/callouts/5.png
Normal file
After Width: | Height: | Size: 348 B |
BIN
railties/guides/images/icons/callouts/6.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
railties/guides/images/icons/callouts/7.png
Normal file
After Width: | Height: | Size: 344 B |
BIN
railties/guides/images/icons/callouts/8.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
railties/guides/images/icons/callouts/9.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
railties/guides/images/icons/caution.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
railties/guides/images/icons/example.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
railties/guides/images/icons/home.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
railties/guides/images/icons/important.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
railties/guides/images/icons/next.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
railties/guides/images/icons/note.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
railties/guides/images/icons/prev.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
railties/guides/images/icons/tip.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
railties/guides/images/icons/up.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
railties/guides/images/icons/warning.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
railties/guides/images/nav_arrow.gif
Normal file
After Width: | Height: | Size: 427 B |
BIN
railties/guides/images/polymorphic.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
railties/guides/images/posts_index.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
railties/guides/images/rails_logo_remix.gif
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
railties/guides/images/rails_welcome.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
railties/guides/images/ruby_guides_logo.gif
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
railties/guides/images/ruby_on_rails_by_mike_rundle2.gif
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
railties/guides/images/session_fixation.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
railties/guides/images/tab_grey.gif
Normal file
After Width: | Height: | Size: 2.4 KiB |