aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb68
-rw-r--r--actionpack/test/dispatch/routing_test.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb24
-rw-r--r--activerecord/test/cases/schema_test_postgresql.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb39
6 files changed, 127 insertions, 31 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 7035e360ec..3e15caee2d 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -55,6 +55,14 @@ module ActionDispatch
path = args.first
end
+ if @scope[:module] && options[:to]
+ if options[:to].to_s.include?("#")
+ options[:to] = "#{@scope[:module]}/#{options[:to]}"
+ elsif @scope[:controller].nil?
+ options[:to] = "#{@scope[:module]}##{options[:to]}"
+ end
+ end
+
path = normalize_path(path)
if using_match_shorthand?(path, options)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 192b365bee..80a00b2a10 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -11,21 +11,25 @@ module ActionView
# Form helpers are designed to make working with resources much easier
# compared to using vanilla HTML.
#
- # Model-based forms are created with +form_for+. That method yields a form
+ # Forms for models are created with +form_for+. That method yields a form
# builder that knows the model the form is about. The form builder is thus
# able to generate default values for input fields that correspond to model
- # attributes, and also convenient element names, IDs, endpoints, etc.
+ # attributes, and also convenient names, IDs, endpoints, etc.
#
# Conventions in the generated field names allow controllers to receive form
# data nicely structured in +params+ with no effort on your side.
#
- # For example, to create a new +Person+ resource you typically set up a new
- # instance in <tt>PeopleController#new</tt> action, <tt>@person</tt>, and
- # write the form in <tt>new.html.erb</tt> this way:
+ # For example, to create a new person you typically set up a new instance of
+ # +Person+ in the <tt>PeopleController#new</tt> action, <tt>@person</tt>, and
+ # pass it to +form_for+:
#
# <%= form_for @person do |f| %>
- # <%= f.text_field :first_name %>
- # <%= f.text_field :last_name %>
+ # <%= f.label :first_name %>:
+ # <%= f.text_field :first_name %><br />
+ #
+ # <%= f.label :last_name %>:
+ # <%= f.text_field :last_name %><br />
+ #
# <%= f.submit %>
# <% end %>
#
@@ -35,16 +39,54 @@ module ActionView
# <div style="margin:0;padding:0;display:inline">
# <input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" />
# </div>
- # <input id="person_first_name" name="person[first_name]" size="30" type="text" />
- # <input id="person_last_name" name="person[last_name]" size="30" type="text" />
+ # <label for="person_first_name">First name</label>:
+ # <input id="person_first_name" name="person[first_name]" size="30" type="text" /><br />
+ #
+ # <label for="person_last_name">Last name</label>:
+ # <input id="person_last_name" name="person[last_name]" size="30" type="text" /><br />
+ #
# <input id="person_submit" name="commit" type="submit" value="Create Person" />
# </form>
#
- # Because of the names of the input fields, the controller gets a <tt>:person</tt>
- # nested hash in +params+ with the corresponding first and last names. That hash
- # is ready to be passed to <tt>Person.create</tt> like this:
+ # As you see, the HTML reflects knowledge about the resource in several spots,
+ # like the path the form should be submitted to, or the names of the input fields.
+ #
+ # In particular, thanks to the conventions followed in the generated field names, the
+ # controller gets a nested hash <tt>params[:person]</tt> with the person attributes
+ # set in the form. That hash is ready to be passed to <tt>Person.create</tt>:
+ #
+ # if @person = Person.create(params[:person])
+ # # success
+ # else
+ # # error handling
+ # end
+ #
+ # Interestingly, the exact same view code in the previous example can be used to edit
+ # a person. If <tt>@person</tt> is an existing record with name "John Smith" and ID 256,
+ # the code above as is would yield instead:
+ #
+ # <form action="/people/256" class="edit_person" id="edit_person_256" method="post">
+ # <div style="margin:0;padding:0;display:inline">
+ # <input name="_method" type="hidden" value="put" />
+ # <input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" />
+ # </div>
+ # <label for="person_first_name">First name</label>:
+ # <input id="person_first_name" name="person[first_name]" size="30" type="text" value="John" /><br />
+ #
+ # <label for="person_last_name">Last name</label>:
+ # <input id="person_last_name" name="person[last_name]" size="30" type="text" value="Smith" /><br />
+ #
+ # <input id="person_submit" name="commit" type="submit" value="Update Person" />
+ # </form>
+ #
+ # Note that the endpoint, default values, and submit button label are tailored for <tt>@person</tt>.
+ # That works that way because the involved helpers know whether the resource is a new record or not,
+ # and generate HTML accordingly.
+ #
+ # The controller would receive the form data again in <tt>params[:person]</tt>, ready to be
+ # passed to <tt>Person#update_attributes</tt>:
#
- # if person = Person.create(params[:person])
+ # if @person.update_attributes(params[:person])
# # success
# else
# # error handling
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index d38c48bfd4..411a28d8ee 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -140,7 +140,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
namespace :account do
match 'shorthand'
- match 'description', :to => "account#description", :as => "description"
+ match 'description', :to => "description", :as => "description"
resource :subscription, :credit, :credit_card
root :to => "account#index"
@@ -864,7 +864,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
with_test_routes do
assert_equal '/account', account_root_path
get '/account'
- assert_equal 'account#index', @response.body
+ assert_equal 'account/account#index', @response.body
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 7169c8f3f0..ceb1adc9e0 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -670,8 +670,30 @@ module ActiveRecord
def tables(name = nil)
query(<<-SQL, name).map { |row| row[0] }
SELECT tablename
+ FROM pg_tables
+ WHERE schemaname = ANY (current_schemas(false))
+ SQL
+ end
+
+ def table_exists?(name)
+ name = name.to_s
+ schema, table = name.split('.', 2)
+
+ unless table # A table was provided without a schema
+ table = schema
+ schema = nil
+ end
+
+ if name =~ /^"/ # Handle quoted table names
+ table = name
+ schema = nil
+ end
+
+ query(<<-SQL).first[0].to_i > 0
+ SELECT COUNT(*)
FROM pg_tables
- WHERE schemaname = ANY (current_schemas(false))
+ WHERE tablename = '#{table.gsub(/(^"|"$)/,'')}'
+ #{schema ? "AND schemaname = '#{schema}'" : ''}
SQL
end
diff --git a/activerecord/test/cases/schema_test_postgresql.rb b/activerecord/test/cases/schema_test_postgresql.rb
index a294848fa3..3ed73786a7 100644
--- a/activerecord/test/cases/schema_test_postgresql.rb
+++ b/activerecord/test/cases/schema_test_postgresql.rb
@@ -52,6 +52,21 @@ class SchemaTest < ActiveRecord::TestCase
@connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE"
end
+ def test_table_exists?
+ [Thing1, Thing2, Thing3, Thing4].each do |klass|
+ name = klass.table_name
+ assert @connection.table_exists?(name), "'#{name}' table should exist"
+ end
+ end
+
+ def test_table_exists_wrong_schema
+ assert(!@connection.table_exists?("foo.things"), "table should not exist")
+ end
+
+ def test_table_exists_quoted_table
+ assert(@connection.table_exists?('"things.table"'), "table should exist")
+ end
+
def test_with_schema_prefixed_table_name
assert_nothing_raised do
assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}")
diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb
index 725acad43a..d2bcd7a778 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute.rb
@@ -1,5 +1,4 @@
require 'active_support/core_ext/kernel/singleton_class'
-require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/module/remove_method'
class Class
@@ -41,21 +40,31 @@ class Class
def class_attribute(*attrs)
instance_writer = !attrs.last.is_a?(Hash) || attrs.pop[:instance_writer]
- s = singleton_class
- attrs.each do |attr|
- s.send(:define_method, attr) { }
- s.send(:define_method, :"#{attr}?") { !!send(attr) }
- s.send(:define_method, :"#{attr}=") do |value|
- singleton_class.remove_possible_method(attr)
- singleton_class.send(:define_method, attr) { value }
- end
+ attrs.each do |name|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def self.#{name}() nil end
+ def self.#{name}?() !!#{name} end
+
+ def self.#{name}=(val)
+ singleton_class.class_eval do
+ remove_possible_method(:#{name})
+ define_method(:#{name}) { val }
+ end
+ end
+
+ def #{name}
+ defined?(@#{name}) ? @#{name} : singleton_class.#{name}
+ end
- define_method(attr) { self.singleton_class.send(attr) }
- define_method(:"#{attr}?") { !!send(attr) }
- define_method(:"#{attr}=") do |value|
- singleton_class.remove_possible_method(attr)
- singleton_class.send(:define_method, attr) { value }
- end if instance_writer
+ def #{name}?
+ !!#{name}
+ end
+ RUBY
+
+ if instance_writer
+ body = "def #{name}=(value) @#{name} = value end"
+ class_eval body, __FILE__, __LINE__ - 1
+ end
end
end
end