From 3008994d1e29b7e59a64bf0a03b5408a2946db25 Mon Sep 17 00:00:00 2001 From: Sam Ruby Date: Wed, 13 Mar 2013 08:08:56 -0400 Subject: Add support for generate scaffold password:digest * adds password_digest attribute to the migration * adds has_secure_password to the model * adds password and password_confirmation password_fields to _form.html * omits password entirely from index.html and show.html * adds password and password_confirmation to the controller * adds unencrypted password and password_confirmation to the controller test * adds encrypted password_digest to the fixture --- .../migration/templates/create_table_migration.rb | 4 +++ .../active_record/model/templates/model.rb | 5 ++- railties/CHANGELOG.md | 12 +++++++ .../erb/scaffold/templates/_form.html.erb | 9 +++++ .../erb/scaffold/templates/index.html.erb | 4 +-- .../erb/scaffold/templates/show.html.erb | 2 +- .../lib/rails/generators/generated_attribute.rb | 4 +++ railties/lib/rails/generators/named_base.rb | 1 + .../test_unit/model/templates/fixtures.yml | 16 ++++----- .../test_unit/scaffold/scaffold_generator.rb | 6 +++- .../test/generators/scaffold_generator_test.rb | 41 ++++++++++++++++++++++ 11 files changed, 90 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb index 3a3cf86d73..fd94a2d038 100644 --- a/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +++ b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb @@ -2,8 +2,12 @@ class <%= migration_class_name %> < ActiveRecord::Migration def change create_table :<%= table_name %> do |t| <% attributes.each do |attribute| -%> +<% if attribute.password_digest? -%> + t.string :password_digest<%= attribute.inject_options %> +<% else -%> t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %> <% end -%> +<% end -%> <% if options[:timestamps] %> t.timestamps <% end -%> diff --git a/activerecord/lib/rails/generators/active_record/model/templates/model.rb b/activerecord/lib/rails/generators/active_record/model/templates/model.rb index 056f55470c..808598699b 100644 --- a/activerecord/lib/rails/generators/active_record/model/templates/model.rb +++ b/activerecord/lib/rails/generators/active_record/model/templates/model.rb @@ -1,7 +1,10 @@ <% module_namespacing do -%> class <%= class_name %> < <%= parent_class_name.classify %> -<% attributes.select {|attr| attr.reference? }.each do |attribute| -%> +<% attributes.select(&:reference?).each do |attribute| -%> belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %> <% end -%> +<% if attributes.any?(&:password_digest?) -%> + has_secure_password +<% end -%> end <% end -%> diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index bbc7d31f33..60a823de15 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,17 @@ ## Rails 4.0.0 (unreleased) ## +* Add support for generate scaffold password:digest + + * adds password_digest attribute to the migration + * adds has_secure_password to the model + * adds password and password_confirmation password_fields to _form.html + * omits password from index.html and show.html + * adds password and password_confirmation to the controller + * adds unencrypted password and password_confirmation to the controller test + * adds encrypted password_digest to the fixture + + *Sam Ruby* + * Rails now generates a `test/test_helper.rb` file with `fixtures :all` commented out by default, since we don't want to force loading all fixtures for user when a single test is run. However, fixtures are still going to be loaded automatically for test suites. diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 32546936e3..85a1b01cc6 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -13,8 +13,17 @@ <% attributes.each do |attribute| -%>
+<% if attribute.password_digest? -%> + <%%= f.label :password %>
+ <%%= f.password_field :password %> +
+
+ <%%= f.label :password_confirmation %>
+ <%%= f.password_field :password_confirmation %> +<% else -%> <%%= f.label :<%= attribute.name %> %>
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> +<% end -%>
<% end -%>
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index 90d8db1df5..d2fd99fdcb 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -3,7 +3,7 @@ -<% attributes.each do |attribute| -%> +<% attributes.reject(&:password_digest?).each do |attribute| -%> <% end -%> @@ -15,7 +15,7 @@ <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %> -<% attributes.each do |attribute| -%> +<% attributes.reject(&:password_digest?).each do |attribute| -%> <% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index daae72270f..5e634153be 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -1,6 +1,6 @@

<%%= notice %>

-<% attributes.each do |attribute| -%> +<% attributes.reject(&:password_digest?).each do |attribute| -%>

<%= attribute.human_name %>: <%%= @<%= singular_table_name %>.<%= attribute.name %> %> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 4ae8756ed0..5e2784c4b0 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -130,6 +130,10 @@ module Rails @has_uniq_index end + def password_digest? + name == 'password' && type == :digest + end + def inject_options "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } end diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 9965db98de..8b4f52bb3b 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -163,6 +163,7 @@ module Rails def attributes_names @attributes_names ||= attributes.each_with_object([]) do |a, names| names << a.column_name + names << 'password_confirmation' if a.password_digest? names << "#{a.name}_type" if a.polymorphic? end end diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index c9d505c84a..90a92e6982 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml @@ -1,22 +1,20 @@ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html - <% unless attributes.empty? -%> -one: +<% %w(one two).each do |name| %> +<%= name %>: <% attributes.each do |attribute| -%> + <%- if attribute.password_digest? -%> + password_digest: <%%= BCrypt::Password.create('secret') %> + <%- else -%> <%= yaml_key_value(attribute.column_name, attribute.default) %> - <%- if attribute.polymorphic? -%> - <%= yaml_key_value("#{attribute.name}_type", attribute.human_name) %> <%- end -%> -<% end -%> - -two: -<% attributes.each do |attribute| -%> - <%= yaml_key_value(attribute.column_name, attribute.default) %> <%- if attribute.polymorphic? -%> <%= yaml_key_value("#{attribute.name}_type", attribute.human_name) %> <%- end -%> <% end -%> +<% end -%> <% else -%> + # This model initially had no columns defined. If you add columns to the # model remove the '{}' from the fixture names and add the columns immediately # below each fixture, per the syntax in the comments below diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index 8f3ecaadea..2e1f55f2a6 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -21,7 +21,11 @@ module TestUnit # :nodoc: return if attributes_names.empty? attributes_names.map do |name| - "#{name}: @#{singular_table_name}.#{name}" + if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?) + "#{name}: 'secret'" + else + "#{name}: @#{singular_table_name}.#{name}" + end end.sort.join(', ') end end diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 357f472a3f..b29d1e018e 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -271,4 +271,45 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end end end + + def test_scaffold_generator_password_digest + run_generator ["user", "name", "password:digest"] + + assert_file "app/models/user.rb", /has_secure_password/ + + assert_migration "db/migrate/create_users.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.string :name/, up) + assert_match(/t\.string :password_digest/, up) + end + end + + assert_file "app/controllers/users_controller.rb" do |content| + assert_instance_method :user_params, content do |m| + assert_match(/permit\(:name, :password, :password_confirmation\)/, m) + end + end + + assert_file "app/views/users/_form.html.erb" do |content| + assert_match(/<%= f\.password_field :password %>/, content) + assert_match(/<%= f\.password_field :password_confirmation %>/, content) + end + + assert_file "app/views/users/index.html.erb" do |content| + assert_no_match(/password/, content) + end + + assert_file "app/views/users/show.html.erb" do |content| + assert_no_match(/password/, content) + end + + assert_file "test/controllers/users_controller_test.rb" do |content| + assert_match(/password: 'secret'/, content) + assert_match(/password_confirmation: 'secret'/, content) + end + + assert_file "test/fixtures/users.yml" do |content| + assert_match(/password_digest: <%= BCrypt::Password.create\('secret'\) %>/, content) + end + end end -- cgit v1.2.3

<%= attribute.human_name %>
<%%= <%= singular_table_name %>.<%= attribute.name %> %><%%= link_to 'Show', <%= singular_table_name %> %>