diff options
author | Stefan Wintermeyer <stefan.wintermeyer@amooma.de> | 2012-12-17 12:05:14 +0100 |
---|---|---|
committer | Stefan Wintermeyer <stefan.wintermeyer@amooma.de> | 2012-12-17 12:05:14 +0100 |
commit | eaad37485fe59d0306c37cc038dda6d210052910 (patch) | |
tree | 072c4b0e33d442528555b82c415f5e7a1712b2b0 /lib/generators | |
parent | 3e706c2025ecc5523e81ad649639ef2ff75e7bac (diff) | |
parent | b80bd744ad873f6fc43018bc4bfb90677de167bd (diff) |
Merge branch 'develop'
Diffstat (limited to 'lib/generators')
90 files changed, 2279 insertions, 0 deletions
diff --git a/lib/generators/nifty.rb b/lib/generators/nifty.rb new file mode 100644 index 0000000..1c3d6d7 --- /dev/null +++ b/lib/generators/nifty.rb @@ -0,0 +1,28 @@ +require 'rails/generators/base' + +module Nifty + module Generators + class Base < Rails::Generators::Base #:nodoc: + def self.source_root + @_nifty_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'nifty', generator_name, 'templates')) + end + + def self.banner + "rails generate nifty:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]" + end + + private + + def add_gem(name, options = {}) + gemfile_content = File.read(destination_path("Gemfile")) + File.open(destination_path("Gemfile"), 'a') { |f| f.write("\n") } unless gemfile_content =~ /\n\Z/ + gem name, options unless gemfile_content.include? name + end + + def print_usage + self.class.help(Thor::Base.shell.new) + exit + end + end + end +end diff --git a/lib/generators/nifty/authentication/USAGE b/lib/generators/nifty/authentication/USAGE new file mode 100644 index 0000000..89f0a64 --- /dev/null +++ b/lib/generators/nifty/authentication/USAGE @@ -0,0 +1,50 @@ +Description: + Generates a user model, users controller, and sessions controller. The + users controller handles the registration and the sessions controller + handles authentication. This is similar to restful_authentication, but + simpler. + + IMPORTANT: This generator uses the "title" helper method which is generated + by the nifty_layout generator. You may want to run that generator first. + +Usage: + If you do not pass any arguments, the model name will default to "user", and + the authentication controller will default to "session". You can override + each of these respectively by passing one or two arguments. Either name can + be CamelCased or under_scored. + + Make sure to setup the authlogic gem if you are using that option. + + gem "authlogic" # in Gemfile + +Examples: + rails generate nifty:authentication + + Creates user model, users_controller, and sessions_controller. + + rails generate nifty:authentication account + + Creates account model, accounts_controller, and sessions_controller. + + rails generate nifty:authentication Account UserSession + + Creates account model, accounts_controller, and user_sessions_controller. + +Methods: + There are several methods generated which you can use in your application. + Here's a common example of what you might add to your layout. + + <% if logged_in? %> + Welcome <%= current_user.username %>! Not you? + <%= link_to "Log out", logout_path %> + <% else %> + <%= link_to "Sign up", signup_path %> or + <%= link_to "log in", login_path %>. + <% end %> + + You can also restrict unregistered users from accessing a controller using + a before filter. For example. + + before_filter :login_required, :except => [:index, :show] + + See the generated file lib/authentication.rb for details.
\ No newline at end of file diff --git a/lib/generators/nifty/authentication/authentication_generator.rb b/lib/generators/nifty/authentication/authentication_generator.rb new file mode 100644 index 0000000..d4dcbde --- /dev/null +++ b/lib/generators/nifty/authentication/authentication_generator.rb @@ -0,0 +1,154 @@ +require 'generators/nifty' +require 'rails/generators/migration' + +module Nifty + module Generators + class AuthenticationGenerator < Base + include Rails::Generators::Migration + + argument :user_name, :type => :string, :default => 'user', :banner => 'user_name' + argument :session_name, :type => :string, :default => '[[DEFAULT]]', :banner => 'sessions_controller_name' + + class_option :testunit, :desc => 'Use test/unit for test files.', :group => 'Test framework', :type => :boolean + class_option :rspec, :desc => 'Use RSpec for test files.', :group => 'Test framework', :type => :boolean + class_option :shoulda, :desc => 'Use shoulda for test files.', :group => 'Test framework', :type => :boolean + + class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean + class_option :authlogic, :desc => 'Use Authlogic for authentication.', :type => :boolean + + def add_gems + add_gem "bcrypt-ruby", :require => "bcrypt" + add_gem "mocha", :group => :test + end + + def create_model_files + template 'user.rb', "app/models/#{user_singular_name}.rb" + template 'authlogic_session.rb', "app/models/#{user_singular_name}_session.rb" if options.authlogic? + end + + def create_controller_files + template 'users_controller.rb', "app/controllers/#{user_plural_name}_controller.rb" + template 'sessions_controller.rb', "app/controllers/#{session_plural_name}_controller.rb" + end + + def create_helper_files + template 'users_helper.rb', "app/helpers/#{user_plural_name}_helper.rb" + template 'sessions_helper.rb', "app/helpers/#{session_plural_name}_helper.rb" + end + + def create_view_files + template "views/#{view_language}/signup.html.#{view_language}", "app/views/#{user_plural_name}/new.html.#{view_language}" + template "views/#{view_language}/edit.html.#{view_language}", "app/views/#{user_plural_name}/edit.html.#{view_language}" + template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{user_plural_name}/_form.html.#{view_language}" + template "views/#{view_language}/login.html.#{view_language}", "app/views/#{session_plural_name}/new.html.#{view_language}" + end + + def create_lib_files + template 'controller_authentication.rb', 'lib/controller_authentication.rb' + end + + def create_routes + route "resources #{user_plural_name.to_sym.inspect}" + route "resources #{session_plural_name.to_sym.inspect}" + route "match 'login' => '#{session_plural_name}#new', :as => :login" + route "match 'logout' => '#{session_plural_name}#destroy', :as => :logout" + route "match 'signup' => '#{user_plural_name}#new', :as => :signup" + route "match '#{user_singular_name}/edit' => '#{user_plural_name}#edit', :as => :edit_current_#{user_singular_name}" + end + + def create_migration + migration_template 'migration.rb', "db/migrate/create_#{user_plural_name}.rb" + end + + def load_and_include_authentication + inject_into_class "config/application.rb", "Application", " config.autoload_paths << \"\#{config.root}/lib\"" + inject_into_class "app/controllers/application_controller.rb", "ApplicationController", " include ControllerAuthentication\n" + end + + def create_test_files + if test_framework == :rspec + template 'fixtures.yml', "spec/fixtures/#{user_plural_name}.yml" + template 'tests/rspec/user.rb', "spec/models/#{user_singular_name}_spec.rb" + template 'tests/rspec/users_controller.rb', "spec/controllers/#{user_plural_name}_controller_spec.rb" + template 'tests/rspec/sessions_controller.rb', "spec/controllers/#{session_plural_name}_controller_spec.rb" + else + template 'fixtures.yml', "test/fixtures/#{user_plural_name}.yml" + template "tests/#{test_framework}/user.rb", "test/unit/#{user_singular_name}_test.rb" + template "tests/#{test_framework}/users_controller.rb", "test/functional/#{user_plural_name}_controller_test.rb" + template "tests/#{test_framework}/sessions_controller.rb", "test/functional/#{session_plural_name}_controller_test.rb" + end + end + + private + + def session_name + @_session_name ||= @session_name == '[[DEFAULT]]' ? + (options.authlogic? ? user_name + '_session' : 'session') : + @session_name + end + + def user_singular_name + user_name.underscore + end + + def user_plural_name + user_singular_name.pluralize + end + + def user_class_name + user_name.camelize + end + + def user_plural_class_name + user_plural_name.camelize + end + + def session_singular_name + session_name.underscore + end + + def session_plural_name + session_singular_name.pluralize + end + + def session_class_name + session_name.camelize + end + + def session_plural_class_name + session_plural_name.camelize + end + + def view_language + options.haml? ? 'haml' : 'erb' + end + + def test_framework + return @test_framework if defined?(@test_framework) + if options.testunit? + return @test_framework = :testunit + elsif options.rspec? + return @test_framework = :rspec + elsif options.shoulda? + return @test_framework = :shoulda + else + return @test_framework = File.exist?(destination_path('spec')) ? :rspec : :testunit + end + end + + def destination_path(path) + File.join(destination_root, path) + end + + # FIXME: Should be proxied to ActiveRecord::Generators::Base + # Implement the required interface for Rails::Generators::Migration. + def self.next_migration_number(dirname) #:nodoc: + if ActiveRecord::Base.timestamped_migrations + Time.now.utc.strftime("%Y%m%d%H%M%S") + else + "%.3d" % (current_migration_number(dirname) + 1) + end + end + end + end +end diff --git a/lib/generators/nifty/authentication/templates/authlogic_session.rb b/lib/generators/nifty/authentication/templates/authlogic_session.rb new file mode 100644 index 0000000..676cfd0 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/authlogic_session.rb @@ -0,0 +1,2 @@ +class <%= session_class_name %> < Authlogic::Session::Base +end diff --git a/lib/generators/nifty/authentication/templates/controller_authentication.rb b/lib/generators/nifty/authentication/templates/controller_authentication.rb new file mode 100644 index 0000000..6d34ab0 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/controller_authentication.rb @@ -0,0 +1,60 @@ +# This module is included in your application controller which makes +# several methods available to all controllers and views. Here's a +# common example you might add to your application layout file. +# +# <%% if logged_in? %> +# Welcome <%%= current_<%= user_singular_name %>.username %>. +# <%%= link_to "Edit profile", edit_current_<%= user_singular_name %>_path %> or +# <%%= link_to "Log out", logout_path %> +# <%% else %> +# <%%= link_to "Sign up", signup_path %> or +# <%%= link_to "log in", login_path %>. +# <%% end %> +# +# You can also restrict unregistered users from accessing a controller using +# a before filter. For example. +# +# before_filter :login_required, :except => [:index, :show] +module ControllerAuthentication + def self.included(controller) + controller.send :helper_method, :current_<%= user_singular_name %>, :logged_in?, :redirect_to_target_or_default + end + +<%- if options[:authlogic] -%> + def current_<%= session_singular_name %> + return @current_<%= session_singular_name %> if defined?(@current_<%= session_singular_name %>) + @current_<%= session_singular_name %> = <%= session_class_name %>.find + end + + def current_<%= user_singular_name %> + return @current_<%= user_singular_name %> if defined?(@current_<%= user_singular_name %>) + @current_<%= user_singular_name %> = current_<%= session_singular_name %> && current_<%= session_singular_name %>.record + end +<%- else -%> + def current_<%= user_singular_name %> + @current_<%= user_singular_name %> ||= <%= user_class_name %>.find(session[:<%= user_singular_name %>_id]) if session[:<%= user_singular_name %>_id] + end +<%- end -%> + + def logged_in? + current_<%= user_singular_name %> + end + + def login_required + unless logged_in? + store_target_location + redirect_to login_url, :alert => "You must first log in or sign up before accessing this page." + end + end + + def redirect_to_target_or_default(default, *args) + redirect_to(session[:return_to] || default, *args) + session[:return_to] = nil + end + + private + + def store_target_location + session[:return_to] = request.url + end +end diff --git a/lib/generators/nifty/authentication/templates/fixtures.yml b/lib/generators/nifty/authentication/templates/fixtures.yml new file mode 100644 index 0000000..c52532b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/fixtures.yml @@ -0,0 +1,24 @@ +# password: "secret" +foo: + username: foo + email: foo@example.com +<%- if options[:authlogic] -%> + persistence_token: d5ddba13ed4408ea2b0a12ab18ed2d2eda086279736bdc121ca726a11f1e4b99217d9c534c2cc4ebb22729349c8c5fdbe1529e1f2c3c5859c62ef4dd9feea25c + crypted_password: 3d16c326648cccafe3d4b4cb024475c381dda92f430dfedf6f933e1f61203bacb6bae2437849bdb43b06be335e23790e4aa03902b3c28c3bbbbe27d501e521f3 + password_salt: n6z_wtpWoIsHgQb5IcFd +<%- else -%> + password_hash: 3488f5f7efecab14b91eb96169e5e1ee518a569f + password_salt: bef65e058905c379436d80d1a32e7374b139e7b0 +<%- end -%> + +bar: + username: bar + email: bar@example.com +<%- if options[:authlogic] -%> + persistence_token: 19e074bd7cb506ab3e7e53e41f24f0ab3221c8cb68111f4c1aa43965114ad734233979a50a9463537487cdca18c279ac91c4bc83693d589625d446493322394c + crypted_password: 3bc9f4113ca645a186765df3d31a9352d0067bf2304ba0cdd6b08a7f3d58c6668ab1762fa3e76aef466ea2ff188399d8e6c40244fa59312bb4112292dac9f7f0 + password_salt: UiAh9ejabnKRxqsiK0xO +<%- else -%> + password_hash: 3488f5f7efecab14b91eb96169e5e1ee518a569f + password_salt: bef65e058905c379436d80d1a32e7374b139e7b0 +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/migration.rb b/lib/generators/nifty/authentication/templates/migration.rb new file mode 100644 index 0000000..c945df3 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/migration.rb @@ -0,0 +1,20 @@ +class Create<%= user_plural_class_name %> < ActiveRecord::Migration + def self.up + create_table :<%= user_plural_name %> do |t| + t.string :username + t.string :email + <%- if options[:authlogic] -%> + t.string :persistence_token + t.string :crypted_password + <%- else -%> + t.string :password_hash + <%- end -%> + t.string :password_salt + t.timestamps + end + end + + def self.down + drop_table :<%= user_plural_name %> + end +end diff --git a/lib/generators/nifty/authentication/templates/sessions_controller.rb b/lib/generators/nifty/authentication/templates/sessions_controller.rb new file mode 100644 index 0000000..65e77c1 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/sessions_controller.rb @@ -0,0 +1,41 @@ +class <%= session_plural_class_name %>Controller < ApplicationController +<%- if options[:authlogic] -%> + def new + @<%= session_singular_name %> = <%= session_class_name %>.new + end + + def create + @<%= session_singular_name %> = <%= session_class_name %>.new(params[:<%= session_singular_name %>]) + if @<%= session_singular_name %>.save + redirect_to_target_or_default root_url, :notice => "Logged in successfully." + else + render :new + end + end + + def destroy + @<%= session_singular_name %> = <%= session_class_name %>.find + @<%= session_singular_name %>.destroy + redirect_to root_url, :notice => "You have been logged out." + end +<%- else -%> + def new + end + + def create + <%= user_singular_name %> = <%= user_class_name %>.authenticate(params[:login], params[:password]) + if <%= user_singular_name %> + session[:<%= user_singular_name %>_id] = <%= user_singular_name %>.id + redirect_to_target_or_default root_url, :notice => "Logged in successfully." + else + flash.now[:alert] = "Invalid login or password." + render :new + end + end + + def destroy + session[:<%= user_singular_name %>_id] = nil + redirect_to root_url, :notice => "You have been logged out." + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/sessions_helper.rb b/lib/generators/nifty/authentication/templates/sessions_helper.rb new file mode 100644 index 0000000..0958537 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/sessions_helper.rb @@ -0,0 +1,2 @@ +module <%= session_plural_class_name %>Helper +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb new file mode 100644 index 0000000..e0953cc --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= session_plural_class_name %>Controller do + fixtures :all + render_views + + it "new action should render new template" do + get :new + response.should render_template(:new) + end + +<%- if options[:authlogic] -%> + it "create action should render new template when authentication is invalid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + response.should render_template(:new) + <%= session_class_name %>.find.should be_nil + end + + it "create action should redirect when authentication is valid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + response.should redirect_to(root_url) + <%= session_class_name %>.find.<%= user_singular_name %>.should == <%= user_plural_name %>(:foo) + end +<%- else -%> + it "create action should render new template when authentication is invalid" do + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + response.should render_template(:new) + session['<%= user_singular_name %>_id'].should be_nil + end + + it "create action should redirect when authentication is valid" do + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + response.should redirect_to(root_url) + session['<%= user_singular_name %>_id'].should == <%= user_class_name %>.first.id + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/user.rb b/lib/generators/nifty/authentication/templates/tests/rspec/user.rb new file mode 100644 index 0000000..a3f7e92 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/user.rb @@ -0,0 +1,83 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= user_class_name %> do +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_class_name %>.new(attributes) + end + + before(:each) do + <%= user_class_name %>.delete_all + end + + it "should be valid" do + new_<%= user_singular_name %>.should be_valid + end + + it "should require username" do + new_<%= user_singular_name %>(:username => '').should have(1).error_on(:username) + end + + it "should require password" do + new_<%= user_singular_name %>(:password => '').should have(1).error_on(:password) + end + + it "should require well formed email" do + new_<%= user_singular_name %>(:email => 'foo@bar@example.com').should have(1).error_on(:email) + end + + it "should validate uniqueness of email" do + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + new_<%= user_singular_name %>(:email => 'bar@example.com').should have(1).error_on(:email) + end + + it "should validate uniqueness of username" do + new_<%= user_singular_name %>(:username => 'uniquename').save! + new_<%= user_singular_name %>(:username => 'uniquename').should have(1).error_on(:username) + end + + it "should not allow odd characters in username" do + new_<%= user_singular_name %>(:username => 'odd ^&(@)').should have(1).error_on(:username) + end + + it "should validate password is longer than 3 characters" do + new_<%= user_singular_name %>(:password => 'bad').should have(1).error_on(:password) + end + + it "should require matching password confirmation" do + new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').should have(1).error_on(:password) + end + + it "should generate password hash and salt on create" do + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + <%= user_singular_name %>.password_hash.should_not be_nil + <%= user_singular_name %>.password_salt.should_not be_nil + end + + it "should authenticate by username" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + <%= user_class_name %>.authenticate('foobar', 'secret').should == <%= user_singular_name %> + end + + it "should authenticate by email" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + <%= user_class_name %>.authenticate('foo@bar.com', 'secret').should == <%= user_singular_name %> + end + + it "should not authenticate bad username" do + <%= user_class_name %>.authenticate('nonexisting', 'secret').should be_nil + end + + it "should not authenticate bad password" do + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + <%= user_class_name %>.authenticate('foobar', 'badpassword').should be_nil + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb new file mode 100644 index 0000000..60bcff9 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb @@ -0,0 +1,56 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= user_plural_class_name %>Controller do + fixtures :all + render_views + + it "new action should render new template" do + get :new + response.should render_template(:new) + end + + it "create action should render new template when model is invalid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + response.should render_template(:new) + end + + it "create action should redirect when model is valid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + response.should redirect_to(root_url) + <%- unless options[:authlogic] -%> + session['<%= user_singular_name %>_id'].should == assigns['<%= user_singular_name %>'].id + <%- end -%> + end + + it "edit action should redirect when not logged in" do + get :edit, :id => "ignored" + response.should redirect_to(login_url) + end + + it "edit action should render edit template" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + response.should render_template(:edit) + end + + it "update action should redirect when not logged in" do + put :update, :id => "ignored" + response.should redirect_to(login_url) + end + + it "update action should render edit template when <%= user_singular_name %> is invalid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + response.should render_template(:edit) + end + + it "update action should redirect when <%= user_singular_name %> is valid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + response.should redirect_to(root_url) + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb new file mode 100644 index 0000000..e2f9005 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb @@ -0,0 +1,40 @@ +require 'test_helper' + +class <%= session_plural_class_name %>ControllerTest < ActionController::TestCase + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end + + context "create action" do + <%- if options[:authlogic] -%> + should "render new template when authentication is invalid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + assert_template 'new' + assert_nil <%= session_class_name %>.find + end + + should "redirect when authentication is valid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + assert_redirected_to root_url + assert_equal <%= user_plural_name %>(:foo), <%= session_class_name %>.find.<%= user_singular_name %> + end + <%- else -%> + should "render new template when authentication is invalid" do + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + assert_template 'new' + assert_nil session['<%= user_singular_name %>_id'] + end + + should "redirect when authentication is valid" do + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + assert_redirected_to root_url + assert_equal <%= user_class_name %>.first.id, session['<%= user_singular_name %>_id'] + end + <%- end -%> + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb new file mode 100644 index 0000000..beb8bf4 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb @@ -0,0 +1,85 @@ +require 'test_helper' + +class <%= user_class_name %>Test < ActiveSupport::TestCase +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_singular_name %> = <%= user_class_name %>.new(attributes) + <%= user_singular_name %>.valid? # run validations + <%= user_singular_name %> + end + + def setup + <%= user_class_name %>.delete_all + end + + should "be valid" do + assert new_<%= user_singular_name %>.valid? + end + + should "require username" do + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:username => '').errors[:username] + end + + should "require password" do + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:password => '').errors[:password] + end + + should "require well formed email" do + assert_equal ["is invalid"], new_<%= user_singular_name %>(:email => 'foo@bar@example.com').errors[:email] + end + + should "validate uniqueness of email" do + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:email => 'bar@example.com').errors[:email] + end + + should "validate uniqueness of username" do + new_<%= user_singular_name %>(:username => 'uniquename').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:username => 'uniquename').errors[:username] + end + + should "not allow odd characters in username" do + assert_equal ["should only contain letters, numbers, or .-_@"], new_<%= user_singular_name %>(:username => 'odd ^&(@)').errors[:username] + end + + should "validate password is longer than 3 characters" do + assert_equal ["is too short (minimum is 4 characters)"], new_<%= user_singular_name %>(:password => 'bad').errors[:password] + end + + should "require matching password confirmation" do + assert_equal ["doesn't match confirmation"], new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').errors[:password] + end + + should "generate password hash and salt on create" do + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + assert <%= user_singular_name %>.password_hash + assert <%= user_singular_name %>.password_salt + end + + should "authenticate by username" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foobar', 'secret') + end + + should "authenticate by email" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foo@bar.com', 'secret') + end + + should "not authenticate bad username" do + assert_nil <%= user_class_name %>.authenticate('nonexisting', 'secret') + end + + should "not authenticate bad password" do + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + assert_nil <%= user_class_name %>.authenticate('foobar', 'badpassword') + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb new file mode 100644 index 0000000..1728329 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb @@ -0,0 +1,61 @@ +require 'test_helper' + +class <%= user_plural_class_name %>ControllerTest < ActionController::TestCase + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end + + context "create action" do + should "render new template when <%= user_singular_name %> is invalid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + should "redirect when <%= user_singular_name %> is valid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to root_url + <%- unless options[:authlogic] -%> + assert_equal assigns['<%= user_singular_name %>'].id, session['<%= user_singular_name %>_id'] + <%- end -%> + end + end + + context "edit action" do + should "redirect when not logged in" do + get :edit, :id => "ignored" + assert_redirected_to login_url + end + + should "render edit template" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + assert_template 'edit' + end + end + + context "update action" do + should "redirect when not logged in" do + put :update, :id => "ignored" + assert_redirected_to login_url + end + + should "render edit template when <%= user_singular_name %> is invalid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + assert_template 'edit' + end + + should "redirect when <%= user_singular_name %> is valid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + assert_redirected_to root_url + end + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb new file mode 100644 index 0000000..fe2a65b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb @@ -0,0 +1,36 @@ +require 'test_helper' + +class <%= session_plural_class_name %>ControllerTest < ActionController::TestCase + def test_new + get :new + assert_template 'new' + end + +<%- if options[:authlogic] -%> + def test_create_invalid + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + assert_template 'new' + assert_nil <%= session_class_name %>.find + end + + def test_create_valid + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + assert_redirected_to root_url + assert_equal <%= user_plural_name %>(:foo), <%= session_class_name %>.find.<%= user_singular_name %> + end +<%- else -%> + def test_create_invalid + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + assert_template 'new' + assert_nil session['<%= user_singular_name %>_id'] + end + + def test_create_valid + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + assert_redirected_to root_url + assert_equal <%= user_class_name %>.first.id, session['<%= user_singular_name %>_id'] + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/user.rb b/lib/generators/nifty/authentication/templates/tests/testunit/user.rb new file mode 100644 index 0000000..c036cf1 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/user.rb @@ -0,0 +1,88 @@ +require 'test_helper' + +class <%= user_class_name %>Test < ActiveSupport::TestCase +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_singular_name %> = <%= user_class_name %>.new(attributes) + <%= user_singular_name %>.valid? # run validations + <%= user_singular_name %> + end + + def setup + <%= user_class_name %>.delete_all + end + + def test_valid + assert new_<%= user_singular_name %>.valid? + end + + def test_require_username + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:username => '').errors[:username] + end + + def test_require_password + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:password => '').errors[:password] + end + + def test_require_well_formed_email + assert_equal ["is invalid"], new_<%= user_singular_name %>(:email => 'foo@bar@example.com').errors[:email] + end + + def test_validate_uniqueness_of_email + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:email => 'bar@example.com').errors[:email] + end + + def test_validate_uniqueness_of_username + new_<%= user_singular_name %>(:username => 'uniquename').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:username => 'uniquename').errors[:username] + end + + def test_validate_odd_characters_in_username + assert_equal ["should only contain letters, numbers, or .-_@"], new_<%= user_singular_name %>(:username => 'odd ^&(@)').errors[:username] + end + + def test_validate_password_length + assert_equal ["is too short (minimum is 4 characters)"], new_<%= user_singular_name %>(:password => 'bad').errors[:password] + end + + def test_require_matching_password_confirmation + assert_equal ["doesn't match confirmation"], new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').errors[:password] + end + + def test_generate_password_hash_and_salt_on_create + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + assert <%= user_singular_name %>.password_hash + assert <%= user_singular_name %>.password_salt + end + + def test_authenticate_by_username + <%= user_class_name %>.delete_all + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foobar', 'secret') + end + + def test_authenticate_by_email + <%= user_class_name %>.delete_all + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foo@bar.com', 'secret') + end + + def test_authenticate_bad_username + assert_nil <%= user_class_name %>.authenticate('nonexisting', 'secret') + end + + def test_authenticate_bad_password + <%= user_class_name %>.delete_all + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + assert_nil <%= user_class_name %>.authenticate('foobar', 'badpassword') + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb new file mode 100644 index 0000000..ef8a3f7 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb @@ -0,0 +1,53 @@ +require 'test_helper' + +class <%= user_plural_class_name %>ControllerTest < ActionController::TestCase + def test_new + get :new + assert_template 'new' + end + + def test_create_invalid + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + def test_create_valid + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to root_url + <%- unless options[:authlogic] -%> + assert_equal assigns['<%= user_singular_name %>'].id, session['<%= user_singular_name %>_id'] + <%- end -%> + end + + def test_edit_without_user + get :edit, :id => "ignored" + assert_redirected_to login_url + end + + def test_edit + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + assert_template 'edit' + end + + def test_update_without_user + put :update, :id => "ignored" + assert_redirected_to login_url + end + + def test_update_invalid + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + assert_template 'edit' + end + + def test_update_valid + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + assert_redirected_to root_url + end +end diff --git a/lib/generators/nifty/authentication/templates/user.rb b/lib/generators/nifty/authentication/templates/user.rb new file mode 100644 index 0000000..ec18524 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/user.rb @@ -0,0 +1,38 @@ +class <%= user_class_name %> < ActiveRecord::Base +<%- if options[:authlogic] -%> + acts_as_authentic +<%- else -%> + # new columns need to be added here to be writable through mass assignment + attr_accessible :username, :email, :password, :password_confirmation + + attr_accessor :password + before_save :prepare_password + + validates_presence_of :username + validates_uniqueness_of :username, :email, :allow_blank => true + validates_format_of :username, :with => /^[-\w\._@]+$/i, :allow_blank => true, :message => "should only contain letters, numbers, or .-_@" + validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i + validates_presence_of :password, :on => :create + validates_confirmation_of :password + validates_length_of :password, :minimum => 4, :allow_blank => true + + # login can be either username or email address + def self.authenticate(login, pass) + <%= user_singular_name %> = find_by_username(login) || find_by_email(login) + return <%= user_singular_name %> if <%= user_singular_name %> && <%= user_singular_name %>.password_hash == <%= user_singular_name %>.encrypt_password(pass) + end + + def encrypt_password(pass) + BCrypt::Engine.hash_secret(pass, password_salt) + end + + private + + def prepare_password + unless password.blank? + self.password_salt = BCrypt::Engine.generate_salt + self.password_hash = encrypt_password(password) + end + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/users_controller.rb b/lib/generators/nifty/authentication/templates/users_controller.rb new file mode 100644 index 0000000..2faed00 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/users_controller.rb @@ -0,0 +1,32 @@ +class <%= user_plural_class_name %>Controller < ApplicationController + before_filter :login_required, :except => [:new, :create] + + def new + @<%= user_singular_name %> = <%= user_class_name %>.new + end + + def create + @<%= user_singular_name %> = <%= user_class_name %>.new(params[:<%= user_singular_name %>]) + if @<%= user_singular_name %>.save + <%- unless options[:authlogic] -%> + session[:<%= user_singular_name %>_id] = @<%= user_singular_name %>.id + <%- end -%> + redirect_to root_url, :notice => "Thank you for signing up! You are now logged in." + else + render :new + end + end + + def edit + @<%= user_singular_name %> = current_<%= user_singular_name %> + end + + def update + @<%= user_singular_name %> = current_<%= user_singular_name %> + if @<%= user_singular_name %>.update_attributes(params[:<%= user_singular_name %>]) + redirect_to root_url, :notice => "Your profile has been updated." + else + render :edit + end + end +end diff --git a/lib/generators/nifty/authentication/templates/users_helper.rb b/lib/generators/nifty/authentication/templates/users_helper.rb new file mode 100644 index 0000000..7eb9040 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/users_helper.rb @@ -0,0 +1,2 @@ +module <%= user_plural_class_name %>Helper +end diff --git a/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb b/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb new file mode 100644 index 0000000..4e1c47d --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb @@ -0,0 +1,20 @@ +<%%= form_for @<%= user_singular_name %> do |f| %> + <%%= f.error_messages %> + <div class="field"> + <%%= f.label :username %> + <%%= f.text_field :username %> + </div> + <div class="field"> + <%%= f.label :email, "Email Address" %> + <%%= f.text_field :email %> + </div> + <div class="field"> + <%%= f.label :password %> + <%%= f.password_field :password %> + </div> + <div class="field"> + <%%= f.label :password_confirmation, "Confirm Password" %> + <%%= f.password_field :password_confirmation %> + </div> + <div class="actions"><%%= f.submit (@<%= user_singular_name %>.new_record? ? "Sign up" : "Update") %></div> +<%% end %> diff --git a/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb b/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb new file mode 100644 index 0000000..75de67e --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb @@ -0,0 +1,3 @@ +<%% title "Update Profile" %> + +<%%= render "form" %> diff --git a/lib/generators/nifty/authentication/templates/views/erb/login.html.erb b/lib/generators/nifty/authentication/templates/views/erb/login.html.erb new file mode 100644 index 0000000..1cbc428 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/login.html.erb @@ -0,0 +1,30 @@ +<%% title "Log in" %> + +<p>Don't have an account? <%%= link_to "Sign up!", signup_path %></p> + +<%- if options[:authlogic] -%> +<%%= form_for @<%= session_singular_name %> do |f| %> + <%%= f.error_messages %> + <div class="field"> + <%%= f.label :username %> + <%%= f.text_field :username %> + </div> + <div class="field"> + <%%= f.label :password %> + <%%= f.password_field :password %> + </div> + <div class="actions"><%%= f.submit "Log in" %></div> +<%% end %> +<%- else -%> +<%%= form_tag <%= session_plural_name %>_path do %> + <div class="field"> + <%%= label_tag :login, "Username or Email Address" %> + <%%= text_field_tag :login, params[:login] %> + </div> + <div class="field"> + <%%= label_tag :password %> + <%%= password_field_tag :password %> + </div> + <div class="actions"><%%= submit_tag "Log in" %></div> +<%% end %> +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb b/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb new file mode 100644 index 0000000..6f282b5 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb @@ -0,0 +1,5 @@ +<%% title "Sign up" %> + +<p>Already have an account? <%%= link_to "Log in", login_path %>.</p> + +<%%= render "form" %> diff --git a/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml b/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml new file mode 100644 index 0000000..992ee9c --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml @@ -0,0 +1,16 @@ += form_for @<%= user_singular_name %> do |f| + = f.error_messages + .field + = f.label :username + = f.text_field :username + .field + = f.label :email, "Email Address" + = f.text_field :email + .field + = f.label :password + = f.password_field :password + .field + = f.label :password_confirmation, "Confirm Password" + = f.password_field :password_confirmation + .actions + = f.submit (@<%= user_singular_name %>.new_record? ? "Sign up" : "Update") diff --git a/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml b/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml new file mode 100644 index 0000000..4b43a3b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml @@ -0,0 +1,3 @@ +- title "Sign up" + += render "form" diff --git a/lib/generators/nifty/authentication/templates/views/haml/login.html.haml b/lib/generators/nifty/authentication/templates/views/haml/login.html.haml new file mode 100644 index 0000000..22fc95b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/login.html.haml @@ -0,0 +1,26 @@ +- title "Log in" + +%p== Don't have an account? #{link_to "Sign up!", signup_path} + +<%- if options[:authlogic] -%> += form_for @<%= session_singular_name %> do |f| + = f.error_messages + .field + = f.label :username + = f.text_field :username + .field + = f.label :password + = f.password_field :password + .actions + = f.submit "Log in" +<%- else -%> +- form_tag <%= session_plural_name %>_path do + .field + = label_tag :login, "Username or Email Address" + = text_field_tag :login, params[:login] + .field + = label_tag :password + = password_field_tag :password + .actions + = submit_tag "Log in" +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml b/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml new file mode 100644 index 0000000..dc75c13 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml @@ -0,0 +1,5 @@ +- title "Sign up" + +%p== Already have an account? #{link_to "Log in", login_path}. + += render "form" diff --git a/lib/generators/nifty/config/USAGE b/lib/generators/nifty/config/USAGE new file mode 100644 index 0000000..f98972c --- /dev/null +++ b/lib/generators/nifty/config/USAGE @@ -0,0 +1,23 @@ +Description: + The nifty_config generator creates YAML file in your config + directory and an initializer to load this config. The config has a + separate section for each environment. This is a great place to put + any config settings you don't want in your app. + + The config is loaded into a constant called APP_CONFIG by default, + this changes depending on the name you choose to pass the generator. + Use this constant to access the config settings like this. + + APP_CONFIG[:some_setting] + + +Examples: + rails generate nifty:config + + Config: config/app_config.yml + Initializer: config/initializers/load_app_config.rb + + rails generate nifty:config passwords + + Config: config/passwords_config.yml + Initializer: config/initializers/load_passwords_config.rb diff --git a/lib/generators/nifty/config/config_generator.rb b/lib/generators/nifty/config/config_generator.rb new file mode 100644 index 0000000..811c80e --- /dev/null +++ b/lib/generators/nifty/config/config_generator.rb @@ -0,0 +1,24 @@ +require 'generators/nifty' + +module Nifty + module Generators + class ConfigGenerator < Base + argument :config_name, :type => :string, :default => 'app', :banner => 'config_name' + + def create_config + template "load_config.rb", "config/initializers/load_#{file_name}_config.rb" + copy_file "config.yml", "config/#{file_name}_config.yml" + end + + private + + def file_name + config_name.underscore + end + + def constant_name + config_name.underscore.upcase + end + end + end +end diff --git a/lib/generators/nifty/config/templates/config.yml b/lib/generators/nifty/config/templates/config.yml new file mode 100644 index 0000000..3a26ebc --- /dev/null +++ b/lib/generators/nifty/config/templates/config.yml @@ -0,0 +1,8 @@ +development: + domain: localhost:3000 + +test: + domain: test.host + +production: + domain: example.com diff --git a/lib/generators/nifty/config/templates/load_config.rb b/lib/generators/nifty/config/templates/load_config.rb new file mode 100644 index 0000000..06e6a52 --- /dev/null +++ b/lib/generators/nifty/config/templates/load_config.rb @@ -0,0 +1,2 @@ +raw_config = File.read("#{Rails.root}/config/<%= file_name %>_config.yml") +<%= constant_name %>_CONFIG = YAML.load(raw_config)[Rails.env].symbolize_keys diff --git a/lib/generators/nifty/layout/USAGE b/lib/generators/nifty/layout/USAGE new file mode 100644 index 0000000..f94af0d --- /dev/null +++ b/lib/generators/nifty/layout/USAGE @@ -0,0 +1,25 @@ +Description: + The nifty_layout generator creates a basic layout, stylesheet and + helper which will give some structure to a starting Rails app. + + The generator takes one argument which will be the name of the + layout and stylesheet files. If no argument is passed then it defaults + to "application". + + The helper module includes some methods which can be called in any + template or partial to set variables to be used in the layout, such as + page title and javascript/stylesheet includes. + +Examples: + rails generate nifty:layout + + Layout: app/views/layouts/application.html.erb + Stylesheet: public/stylesheets/application.css + Helper: app/helpers/layout_helper.rb + + + rails generate nifty:layout admin + + Layout: app/views/layouts/admin.html.erb + Stylesheet: public/stylesheets/admin.css + Helper: app/helpers/layout_helper.rb diff --git a/lib/generators/nifty/layout/layout_generator.rb b/lib/generators/nifty/layout/layout_generator.rb new file mode 100644 index 0000000..fb7f9f4 --- /dev/null +++ b/lib/generators/nifty/layout/layout_generator.rb @@ -0,0 +1,29 @@ +require 'generators/nifty' + +module Nifty + module Generators + class LayoutGenerator < Base + argument :layout_name, :type => :string, :default => 'application', :banner => 'layout_name' + + class_option :haml, :desc => 'Generate HAML for view, and SASS for stylesheet.', :type => :boolean, :default => true + + def create_layout + if options.haml? + template 'layout.html.haml', "app/views/layouts/#{file_name}.html.haml" + copy_file 'stylesheet.sass', "public/stylesheets/sass/#{file_name}.sass" + else + template 'layout.html.erb', "app/views/layouts/#{file_name}.html.erb" + copy_file 'stylesheet.css', "public/stylesheets/#{file_name}.css" + end + copy_file 'layout_helper.rb', 'app/helpers/layout_helper.rb' + copy_file 'error_messages_helper.rb', 'app/helpers/error_messages_helper.rb' + end + + private + + def file_name + layout_name.underscore + end + end + end +end diff --git a/lib/generators/nifty/layout/templates/error_messages_helper.rb b/lib/generators/nifty/layout/templates/error_messages_helper.rb new file mode 100644 index 0000000..8e9c4d3 --- /dev/null +++ b/lib/generators/nifty/layout/templates/error_messages_helper.rb @@ -0,0 +1,23 @@ +module ErrorMessagesHelper + # Render error messages for the given objects. The :message and :header_message options are allowed. + def error_messages_for(*objects) + options = objects.extract_options! + options[:header_message] ||= I18n.t(:"activerecord.errors.header", :default => "Invalid Fields") + options[:message] ||= I18n.t(:"activerecord.errors.message", :default => "Correct the following errors and try again.") + messages = objects.compact.map { |o| o.errors.full_messages }.flatten + unless messages.empty? + content_tag(:div, :class => "error_messages") do + list_items = messages.map { |msg| content_tag(:li, msg.html_safe) } + content_tag(:h2, options[:header_message].html_safe) + content_tag(:p, options[:message].html_safe) + content_tag(:ul, list_items.join.html_safe) + end + end + end + + module FormBuilderAdditions + def error_messages(options = {}) + @template.error_messages_for(@object, options) + end + end +end + +ActionView::Helpers::FormBuilder.send(:include, ErrorMessagesHelper::FormBuilderAdditions) diff --git a/lib/generators/nifty/layout/templates/layout.html.haml b/lib/generators/nifty/layout/templates/layout.html.haml new file mode 100644 index 0000000..24ec1d6 --- /dev/null +++ b/lib/generators/nifty/layout/templates/layout.html.haml @@ -0,0 +1,21 @@ +!!! +%html + + %head + %title + = content_for?(:title) ? yield(:title) : "Untitled" + %meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}/ + = stylesheet_link_tag "application" + = javascript_include_tag "application" + = csrf_meta_tag + = yield(:head) + + %body + #container + - flash.each do |name, msg| + = content_tag :div, msg, :id => "flash_#{name}" + + - if show_title? + %h1= yield(:title) + + = yield diff --git a/lib/generators/nifty/layout/templates/layout_helper.rb b/lib/generators/nifty/layout/templates/layout_helper.rb new file mode 100644 index 0000000..93011d6 --- /dev/null +++ b/lib/generators/nifty/layout/templates/layout_helper.rb @@ -0,0 +1,38 @@ +# These helper methods can be called in your template to set variables to be used in the layout +# This module should be included in all views globally, +# to do so you may need to add this line to your ApplicationController +# helper :layout +module LayoutHelper + + def title(page_title, show_title = true) + content_for(:title) { strip_tags(page_title.to_s) } + @show_title = show_title + end + + def show_title? + @show_title + end + + def stylesheet(*args) + content_for(:head) { stylesheet_link_tag(*args) } + end + + def javascript(*args) + content_for(:head) { javascript_include_tag(*args) } + end + + def translation_missing?(output) + (output =~ /span/ or output.empty?) + end + + def conditional_hint(translation_key) + output = t(translation_key) + return output unless translation_missing?(output) + false + end + + def conditional_t(translation_key) + output = t(translation_key) + strip_tags(output) + end +end
\ No newline at end of file diff --git a/lib/generators/nifty/layout/templates/stylesheet.css b/lib/generators/nifty/layout/templates/stylesheet.css new file mode 100644 index 0000000..448a53f --- /dev/null +++ b/lib/generators/nifty/layout/templates/stylesheet.css @@ -0,0 +1,83 @@ +html, body { + background-color: #4B7399; + font-family: Verdana, Helvetica, Arial; + font-size: 14px; +} + +a img { + border: none; +} + +a { + color: #0000FF; +} + +.clear { + clear: both; + height: 0; + overflow: hidden; +} + +#container { + width: 75%; + margin: 0 auto; + background-color: #FFF; + padding: 20px 40px; + border: solid 1px black; + margin-top: 20px; +} + +#flash_notice, #flash_error, #flash_alert { + padding: 5px 8px; + margin: 10px 0; +} + +#flash_notice { + background-color: #CFC; + border: solid 1px #6C6; +} + +#flash_error, #flash_alert { + background-color: #FCC; + border: solid 1px #C66; +} + +.error_messages { + width: 400px; + border: 2px solid #CF0000; + padding: 0px; + padding-bottom: 12px; + margin-bottom: 20px; + background-color: #f0f0f0; + font-size: 12px; +} + +.error_messages h2 { + text-align: left; + font-weight: bold; + padding: 5px 10px; + font-size: 12px; + margin: 0; + background-color: #c00; + color: #fff; +} + +.error_messages p { + margin: 8px 10px; +} + +.error_messages ul { + margin: 0; +} + +.field_with_errors { + display: inline; +} + +form .field, form .actions { + margin: 10px 0; +} + +form label { + display: block; +} diff --git a/lib/generators/nifty/layout/templates/stylesheet.sass b/lib/generators/nifty/layout/templates/stylesheet.sass new file mode 100644 index 0000000..383bfd3 --- /dev/null +++ b/lib/generators/nifty/layout/templates/stylesheet.sass @@ -0,0 +1,73 @@ +$primary_color: #4b7399 + +body + background-color: $primary_color + font: + family: Verdana, Helvetica, Arial + size: 14px + +a + color: blue + img + border: none + +.clear + clear: both + height: 0 + overflow: hidden + +#container + width: 75% + margin: 0 auto + background: white + padding: 20px 40px + border: solid 1px black + margin-top: 20px + +#flash_notice, +#flash_error, +#flash_alert + padding: 5px 8px + margin: 10px 0 + +#flash_notice + background-color: #ccffcc + border: solid 1px #66cc66 + +#flash_error, +#flash_alert + background-color: #ffcccc + border: solid 1px #cc6666 + +.error_messages + width: 400px + border: 2px solid #cf0000 + padding: 0 + padding-bottom: 12px + margin-bottom: 20px + background-color: #f0f0f0 + font: + size: 12px + h2 + text-align: left + padding: 5px 5px 5px 15px + margin: 0 + font: + weight: bold + size: 12px + background-color: #cc0000 + color: white + p + margin: 8px 10px + ul + margin: 0 + +.field_with_errors + display: inline + +form .field, +form .actions + margin: 10px 0 + +form label + display: block diff --git a/lib/generators/nifty/scaffold/USAGE b/lib/generators/nifty/scaffold/USAGE new file mode 100644 index 0000000..363fd26 --- /dev/null +++ b/lib/generators/nifty/scaffold/USAGE @@ -0,0 +1,51 @@ +Description: + Scaffolds an entire resource, from model and migration to controller and + views. The resource is ready to use as a starting point for your restful, + resource-oriented application. Tests or specs are also generated depending + on if you have a "spec" directory or not. + + IMPORTANT: This generator uses the "title" helper method which is generated + by the nifty_layout generator. You may want to run that generator first. + +Usage: + Pass the name of the model, either CamelCased or under_scored, as the first + argument along with an optional list of attribute pairs and controller actions. + + If no controller actions are specified, they will default to index, show, + new, create, edit, update, and destroy. + + IMPORTANT: If no attribute pairs are specified, no model will be generated. + It will try to determine the attributes from an existing model. + + Attribute pairs are column_name:sql_type arguments specifying the + model's attributes. Timestamps are added by default, so you don't have to + specify them by hand as 'created_at:datetime updated_at:datetime'. + + For example, `nifty:scaffold post name:string content:text hidden:boolean` + gives you a model with those three attributes, a controller that handles + the create/show/update/destroy, forms to create and edit your posts, and + an index that lists them all, as well as a map.resources :posts + declaration in config/routes.rb. + + Adding an "!" in the mix of arguments will invert the passed controller + actions. This will include all 7 controller actitons except the ones + mentioned. This option doesn't affect model attributes. + +Examples: + rails generate nifty:scaffold post + + Will create a controller called "posts" it will contain all seven + CRUD actions along with the views. A model will NOT be created, + instead it will look for an existing model and use those attributes. + + rails generate nifty:scaffold post name:string content:text index new edit + + Will create a Post model and migration file with the name and content + attributes. It will also create a controller with index, new, create, + edit, and update actions. Notice the create and update actions are + added automatically with new and edit. + + rails generate nifty:scaffold post ! show new + + Creates a posts controller (no model) with index, edit, update, and + destroy actions. diff --git a/lib/generators/nifty/scaffold/scaffold_generator.rb b/lib/generators/nifty/scaffold/scaffold_generator.rb new file mode 100644 index 0000000..1283e17 --- /dev/null +++ b/lib/generators/nifty/scaffold/scaffold_generator.rb @@ -0,0 +1,344 @@ +require 'generators/nifty' +require 'rails/generators/migration' +require 'rails/generators/generated_attribute' + +module Nifty + module Generators + class ScaffoldGenerator < Base + include Rails::Generators::Migration + no_tasks { attr_accessor :scaffold_name, :model_attributes, :controller_actions } + + argument :scaffold_name, :type => :string, :required => true, :banner => 'ModelName' + argument :args_for_c_m, :type => :array, :default => [], :banner => 'controller_actions and model:attributes' + + class_option :skip_model, :desc => 'Don\'t generate a model or migration file.', :type => :boolean + class_option :skip_migration, :desc => 'Don\'t generate migration file for model.', :type => :boolean + class_option :skip_timestamps, :desc => 'Don\'t add timestamps to migration file.', :type => :boolean + class_option :skip_controller, :desc => 'Don\'t generate controller, helper, or views.', :type => :boolean + class_option :invert, :desc => 'Generate all controller actions except these mentioned.', :type => :boolean + class_option :namespace_model, :desc => 'If the resource is namespaced, include the model in the namespace.', :type => :boolean + class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean, :default => true + + class_option :testunit, :desc => 'Use test/unit for test files.', :group => 'Test framework', :type => :boolean + class_option :rspec, :desc => 'Use RSpec for test files.', :group => 'Test framework', :type => :boolean + class_option :shoulda, :desc => 'Use shoulda for test files.', :group => 'Test framework', :type => :boolean + + def initialize(*args, &block) + super + + print_usage unless scaffold_name.underscore =~ /^[a-z][a-z0-9_\/]+$/ + + @controller_actions = [] + @model_attributes = [] + @skip_model = options.skip_model? + @namespace_model = options.namespace_model? + @invert_actions = options.invert? + + args_for_c_m.each do |arg| + if arg == '!' + @invert_actions = true + elsif arg.include?(':') + @model_attributes << Rails::Generators::GeneratedAttribute.new(*arg.split(':')) + else + @controller_actions << arg + @controller_actions << 'create' if arg == 'new' + @controller_actions << 'update' if arg == 'edit' + end + end + + @controller_actions.uniq! + @model_attributes.uniq! + + if @invert_actions || @controller_actions.empty? + @controller_actions = all_actions - @controller_actions + end + + if @model_attributes.empty? + @skip_model = true # skip model if no attributes + if model_exists? + model_columns_for_attributes.each do |column| + @model_attributes << Rails::Generators::GeneratedAttribute.new(column.name.to_s, column.type.to_s) + end + else + @model_attributes << Rails::Generators::GeneratedAttribute.new('name', 'string') + end + end + end + + def add_gems + # add_gem "mocha", :group => :test + add_gem 'haml' + add_gem 'simple_form' + add_gem 'cancan' + end + + def create_model + unless @skip_model + template 'model.rb', "app/models/#{model_path}.rb" + if test_framework == :rspec + template "tests/rspec/model.rb", "spec/models/#{model_path}_spec.rb" + # FUCK YOU FIXTURES, WE USE FACTORY GIRL. + # template 'fixtures.yml', "spec/fixtures/#{model_path.pluralize}.yml" + else + template "tests/#{test_framework}/model.rb", "test/unit/#{model_path}_test.rb" + template 'fixtures.yml', "test/fixtures/#{model_path.pluralize}.yml" + end + end + end + + def create_migration + unless @skip_model || options.skip_migration? + migration_template 'migration.rb', "db/migrate/create_#{model_path.pluralize.gsub('/', '_')}.rb" + end + end + + def create_controller + unless options.skip_controller? + template 'controller.rb', "app/controllers/#{plural_name}_controller.rb" + + template 'helper.rb', "app/helpers/#{plural_name}_helper.rb" + + controller_actions.each do |action| + if %w[index show new edit].include?(action) # Actions with templates + template "views/#{view_language}/#{action}.html.#{view_language}", "app/views/#{plural_name}/#{action}.html.#{view_language}" + end + end + + # Move the index_core (can't do it on the top.) + template "views/#{view_language}/_index_core.html.#{view_language}", "app/views/#{plural_name}/_index_core.html.#{view_language}" + + + if form_partial? + template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{plural_name}/_form.html.#{view_language}" + template "views/#{view_language}/_form_core.html.#{view_language}", "app/views/#{plural_name}/_form_core.html.#{view_language}" + end + + namespaces = plural_name.split('/') + resource = namespaces.pop + route namespaces.reverse.inject("resources :#{resource}") { |acc, namespace| + "namespace(:#{namespace}){ #{acc} }" + } + + if test_framework == :rspec + template "tests/#{test_framework}/controller.rb", "spec/controllers/#{plural_name}_controller_spec.rb" + else + template "tests/#{test_framework}/controller.rb", "test/functional/#{plural_name}_controller_test.rb" + end + end + end + + def create_locales + template 'locale.yml', "config/locales/views/#{plural_name}/en.yml" + template 'locale_de.yml', "config/locales/views/#{plural_name}/de.yml" + # template 'locale.yml', "config/locales/views/#{plural_name}/es.yml" + # gsub_file("config/locales/views/#{plural_name}/es.yml", 'en:', 'es:') + # gsub_file("config/locales/views/#{plural_name}/de.yml", 'en:', 'de:') + end + + def configuration + gsub_file('config/application.rb', "# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]", + "config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*', '*', '*.{rb,yml}').to_s]") + end + + private + + def form_partial? + actions? :new, :edit + end + + def all_actions + %w[index show new create edit update destroy] + end + + def action?(name) + controller_actions.include? name.to_s + end + + def actions?(*names) + names.all? { |name| action? name } + end + + def singular_name + scaffold_name.underscore + end + + def plural_name + scaffold_name.underscore.pluralize + end + + def human_name + scaffold_name.humanize + end + + def table_name + if scaffold_name.include?('::') && @namespace_model + plural_name.gsub('/', '_') + end + end + + def class_name + if @namespace_model + scaffold_name.camelize + else + scaffold_name.split('::').last.camelize + end + end + + def model_path + class_name.underscore + end + + def plural_class_name + plural_name.camelize + end + + def instance_name + if @namespace_model + singular_name.gsub('/','_') + else + singular_name.split('/').last + end + end + + def instances_name + instance_name.pluralize + end + + def controller_methods(dir_name) + controller_actions.map do |action| + read_template("#{dir_name}/#{action}.rb") + end.join("\n").strip + end + + def render_form + if form_partial? + if options.haml? + "= render \"form\"" + else + "<%= render \"form\" %>" + end + else + read_template("views/#{view_language}/_form.html.#{view_language}") + end + end + + def item_resource + scaffold_name.underscore.gsub('/','_') + end + + def items_path + if action? :index + "#{item_resource.pluralize}_path" + else + "root_path" + end + end + + def item_path(options = {}) + name = options[:instance_variable] ? "@#{instance_name}" : instance_name + suffix = options[:full_url] ? "url" : "path" + if options[:action].to_s == "new" + "new_#{item_resource}_#{suffix}" + elsif options[:action].to_s == "edit" + "edit_#{item_resource}_#{suffix}(#{name})" + else + if scaffold_name.include?('::') && !@namespace_model + namespace = singular_name.split('/')[0..-2] + "[:#{namespace.join(', :')}, #{name}]" + else + name + end + end + end + + def item_url + if action? :show + item_path(:full_url => true, :instance_variable => true) + else + items_url + end + end + + def items_url + if action? :index + item_resource.pluralize + '_url' + else + "root_url" + end + end + + def item_path_for_spec(suffix = 'path') + if action? :show + "#{item_resource}_#{suffix}(assigns[:#{instance_name}])" + else + if suffix == 'path' + items_path + else + items_url + end + end + end + + def item_path_for_test(suffix = 'path') + if action? :show + "#{item_resource}_#{suffix}(assigns(:#{instance_name}))" + else + if suffix == 'path' + items_path + else + items_url + end + end + end + + def model_columns_for_attributes + class_name.constantize.columns.reject do |column| + column.name.to_s =~ /^(id|created_at|updated_at)$/ + end + end + + def view_language + options.haml? ? 'haml' : 'erb' + end + + def test_framework + return @test_framework if defined?(@test_framework) + if options.testunit? + return @test_framework = :testunit + elsif options.rspec? + return @test_framework = :rspec + elsif options.shoulda? + return @test_framework = :shoulda + else + return @test_framework = default_test_framework + end + end + + def default_test_framework + File.exist?(destination_path("spec")) ? :rspec : :testunit + end + + def model_exists? + File.exist? destination_path("app/models/#{singular_name}.rb") + end + + def read_template(relative_path) + ERB.new(File.read(find_in_source_paths(relative_path)), nil, '-').result(binding) + end + + def destination_path(path) + File.join(destination_root, path) + end + + # FIXME: Should be proxied to ActiveRecord::Generators::Base + # Implement the required interface for Rails::Generators::Migration. + def self.next_migration_number(dirname) #:nodoc: + if ActiveRecord::Base.timestamped_migrations + Time.now.utc.strftime("%Y%m%d%H%M%S") + else + "%.3d" % (current_migration_number(dirname) + 1) + end + end + end + end +end diff --git a/lib/generators/nifty/scaffold/templates/actions/create.rb b/lib/generators/nifty/scaffold/templates/actions/create.rb new file mode 100644 index 0000000..8365f0b --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/create.rb @@ -0,0 +1,8 @@ + def create + @<%= instance_name %> = <%= class_name %>.new(params[:<%= instance_name %>]) + if @<%= instance_name %>.save + redirect_to <%= item_url %>, :notice => t('<%= plural_name %>.controller.successfuly_created') + else + render :new + end + end diff --git a/lib/generators/nifty/scaffold/templates/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/actions/destroy.rb new file mode 100644 index 0000000..8a236e0 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/destroy.rb @@ -0,0 +1,5 @@ + def destroy + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + @<%= instance_name %>.destroy + redirect_to <%= items_url %>, :notice => t('<%= plural_name %>.controller.successfuly_destroyed') + end diff --git a/lib/generators/nifty/scaffold/templates/actions/edit.rb b/lib/generators/nifty/scaffold/templates/actions/edit.rb new file mode 100644 index 0000000..907e928 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/edit.rb @@ -0,0 +1,3 @@ + def edit + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + end diff --git a/lib/generators/nifty/scaffold/templates/actions/index.rb b/lib/generators/nifty/scaffold/templates/actions/index.rb new file mode 100644 index 0000000..0a8420c --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/index.rb @@ -0,0 +1,3 @@ + def index + @<%= instances_name %> = <%= class_name %>.all + end diff --git a/lib/generators/nifty/scaffold/templates/actions/new.rb b/lib/generators/nifty/scaffold/templates/actions/new.rb new file mode 100644 index 0000000..c0991bc --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/new.rb @@ -0,0 +1,3 @@ + def new + @<%= instance_name %> = <%= class_name %>.new + end diff --git a/lib/generators/nifty/scaffold/templates/actions/show.rb b/lib/generators/nifty/scaffold/templates/actions/show.rb new file mode 100644 index 0000000..27a0467 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/show.rb @@ -0,0 +1,3 @@ + def show + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + end diff --git a/lib/generators/nifty/scaffold/templates/actions/update.rb b/lib/generators/nifty/scaffold/templates/actions/update.rb new file mode 100644 index 0000000..a1473a6 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/update.rb @@ -0,0 +1,8 @@ + def update + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + if @<%= instance_name %>.update_attributes(params[:<%= instance_name %>]) + redirect_to <%= item_url %>, :notice => t('<%= plural_name %>.controller.successfuly_updated') + else + render :edit + end + end diff --git a/lib/generators/nifty/scaffold/templates/controller.rb b/lib/generators/nifty/scaffold/templates/controller.rb new file mode 100644 index 0000000..a54de70 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/controller.rb @@ -0,0 +1,3 @@ +class <%= plural_class_name %>Controller < ApplicationController + <%= controller_methods :actions %> +end diff --git a/lib/generators/nifty/scaffold/templates/fixtures.yml b/lib/generators/nifty/scaffold/templates/fixtures.yml new file mode 100644 index 0000000..447eaf9 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/fixtures.yml @@ -0,0 +1,9 @@ +one: +<%- for attribute in model_attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<%- end -%> + +two: +<%- for attribute in model_attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<%- end -%> diff --git a/lib/generators/nifty/scaffold/templates/helper.rb b/lib/generators/nifty/scaffold/templates/helper.rb new file mode 100644 index 0000000..084b485 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/helper.rb @@ -0,0 +1,2 @@ +module <%= plural_class_name %>Helper +end diff --git a/lib/generators/nifty/scaffold/templates/locale.yml b/lib/generators/nifty/scaffold/templates/locale.yml new file mode 100644 index 0000000..46e4ce3 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/locale.yml @@ -0,0 +1,46 @@ +en: + <%= plural_name %>: + name: '<%= human_name %>' + controller: + successfuly_created: 'Successfully created <%= human_name %>.' + successfuly_updated: 'Successfully updated <%= human_name %>.' + successfuly_destroyed: 'Successfully destroyed <%= human_name %>.' + index: + page_title: 'Listing <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Are you sure you want to delete this <%= human_name %>?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New <%= human_name %> for %{resource}' + show: + page_title: 'Show <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New <%= human_name %>' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing <%= human_name %>' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + <%- for attribute in model_attributes -%> + <%= attribute.name %>: + label: '<%= attribute.human_name %>' + hint: '' + <%- end -%> + button: 'Submit'
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/locale_de.yml b/lib/generators/nifty/scaffold/templates/locale_de.yml new file mode 100644 index 0000000..027d36d --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/locale_de.yml @@ -0,0 +1,46 @@ +de: + <%= plural_name %>: + name: '<%= human_name %>' + controller: + successfuly_created: '<%= human_name %> wurde angelegt.' + successfuly_updated: '<%= human_name %> wurde aktualisiert.' + successfuly_destroyed: '<%= human_name %> wurde gelöscht.' + index: + page_title: 'Übersicht von <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Sind Sie sicher, dass Sie folgendes löschen möchten: <%= human_name %>' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: '<%= human_name %> neu anlegen für %{resource}' + show: + page_title: '<%= human_name %> bearbeiten' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Sind Sie sicher, dass die dieses Element löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: '<%= human_name %> neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: '<%= human_name %> bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + <%- for attribute in model_attributes -%> + <%= attribute.name %>: + label: '<%= attribute.human_name %>' + hint: '' + <%- end -%> + button: 'Absenden'
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/migration.rb b/lib/generators/nifty/scaffold/templates/migration.rb new file mode 100644 index 0000000..02fd6bd --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/migration.rb @@ -0,0 +1,16 @@ +class Create<%= class_name.pluralize.delete('::') %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name || plural_name.split('/').last %> do |t| + <%- for attribute in model_attributes -%> + t.<%= attribute.type %> :<%= attribute.name %> + <%- end -%> + <%- unless options[:skip_timestamps] -%> + t.timestamps + <%- end -%> + end + end + + def self.down + drop_table :<%= table_name || plural_name.split('/').last %> + end +end diff --git a/lib/generators/nifty/scaffold/templates/model.rb b/lib/generators/nifty/scaffold/templates/model.rb new file mode 100644 index 0000000..fe5f980 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/model.rb @@ -0,0 +1,4 @@ +class <%= class_name %> < ActiveRecord::Base +<%= " set_table_name :#{table_name}\n" if table_name -%> + attr_accessible <%= model_attributes.map { |a| ":#{a.name}" }.join(", ") %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb new file mode 100644 index 0000000..ef5a906 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb @@ -0,0 +1,11 @@ + it "create action should render new template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + response.should render_template(:new) + end + + it "create action should redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + response.should redirect_to(<%= item_path_for_spec('url') %>) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb new file mode 100644 index 0000000..8372953 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb @@ -0,0 +1,6 @@ + it "destroy action should destroy model and redirect to index action" do + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + response.should redirect_to(<%= items_url %>) + <%= class_name %>.exists?(<%= instance_name %>.id).should be_false + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb new file mode 100644 index 0000000..e144904 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb @@ -0,0 +1,4 @@ + it "edit action should render edit template" do + get :edit, :id => <%= class_name %>.first + response.should render_template(:edit) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb new file mode 100644 index 0000000..a40ea16 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb @@ -0,0 +1,4 @@ + it "index action should render index template" do + get :index + response.should render_template(:index) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb new file mode 100644 index 0000000..22e1b40 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb @@ -0,0 +1,4 @@ + it "new action should render new template" do + get :new + response.should render_template(:new) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb new file mode 100644 index 0000000..eaa3d93 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb @@ -0,0 +1,4 @@ + it "show action should render show template" do + get :show, :id => <%= class_name %>.first + response.should render_template(:show) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb new file mode 100644 index 0000000..c919962 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb @@ -0,0 +1,11 @@ + it "update action should render edit template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + response.should render_template(:edit) + end + + it "update action should redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + response.should redirect_to(<%= item_path_for_spec('url') %>) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb new file mode 100644 index 0000000..5d97f63 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= plural_class_name %>Controller do + fixtures :all + render_views + + <%= controller_methods 'tests/rspec/actions' %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb new file mode 100644 index 0000000..25c3cc4 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= class_name %> do + it "should be valid" do + <%= class_name %>.new.should be_valid + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb new file mode 100644 index 0000000..f305367 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb @@ -0,0 +1,13 @@ + context "create action" do + should "render new template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + should "redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to <%= item_path_for_test('url') %> + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb new file mode 100644 index 0000000..ea20133 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb @@ -0,0 +1,8 @@ + context "destroy action" do + should "destroy model and redirect to index action" do + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + assert_redirected_to <%= items_url %> + assert !<%= class_name %>.exists?(<%= instance_name %>.id) + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb new file mode 100644 index 0000000..47597d0 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb @@ -0,0 +1,6 @@ + context "edit action" do + should "render edit template" do + get :edit, :id => <%= class_name %>.first + assert_template 'edit' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb new file mode 100644 index 0000000..44b056b --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb @@ -0,0 +1,6 @@ + context "index action" do + should "render index template" do + get :index + assert_template 'index' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb new file mode 100644 index 0000000..5857a55 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb @@ -0,0 +1,6 @@ + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb new file mode 100644 index 0000000..75b37f6 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb @@ -0,0 +1,6 @@ + context "show action" do + should "render show template" do + get :show, :id => <%= class_name %>.first + assert_template 'show' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb new file mode 100644 index 0000000..fc46f72 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb @@ -0,0 +1,13 @@ + context "update action" do + should "render edit template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + assert_template 'edit' + end + + should "redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + assert_redirected_to <%= item_path_for_test('url') %> + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb new file mode 100644 index 0000000..e9f9764 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb @@ -0,0 +1,5 @@ +require 'test_helper' + +class <%= plural_class_name %>ControllerTest < ActionController::TestCase + <%= controller_methods 'tests/shoulda/actions' %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb new file mode 100644 index 0000000..9065963 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= class_name %>Test < ActiveSupport::TestCase + should "be valid" do + assert <%= class_name %>.new.valid? + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb new file mode 100644 index 0000000..5a6d2ac --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb @@ -0,0 +1,11 @@ + def test_create_invalid + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + def test_create_valid + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to <%= item_path_for_test('url') %> + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb new file mode 100644 index 0000000..adedf91 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb @@ -0,0 +1,6 @@ + def test_destroy + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + assert_redirected_to <%= items_url %> + assert !<%= class_name %>.exists?(<%= instance_name %>.id) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb new file mode 100644 index 0000000..55ed24a --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb @@ -0,0 +1,4 @@ + def test_edit + get :edit, :id => <%= class_name %>.first + assert_template 'edit' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb new file mode 100644 index 0000000..22d3bad --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb @@ -0,0 +1,4 @@ + def test_index + get :index + assert_template 'index' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb new file mode 100644 index 0000000..c551327 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb @@ -0,0 +1,4 @@ + def test_new + get :new + assert_template 'new' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb new file mode 100644 index 0000000..b74f371 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb @@ -0,0 +1,4 @@ + def test_show + get :show, :id => <%= class_name %>.first + assert_template 'show' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb new file mode 100644 index 0000000..b588bfc --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb @@ -0,0 +1,11 @@ + def test_update_invalid + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + assert_template 'edit' + end + + def test_update_valid + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + assert_redirected_to <%= item_path_for_test('url') %> + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb new file mode 100644 index 0000000..8b99836 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class <%= plural_class_name %>ControllerTest < ActionController::TestCase + setup do + <%= item_path :instance_variable => true %> = <%= plural_name %>(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:<%= plural_name %>) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create <%= item_path %>" do + assert_difference('<%= class_name %>.count') do + post :create, <%= item_path %>: @<%= item_path %>.attributes + end + + assert_redirected_to <%= item_path %>_path(assigns(:<%= item_path %>)) + end + + test "should show <%= item_path %>" do + get :show, id: @<%= item_path %>.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @<%= item_path %>.to_param + assert_response :success + end + + test "should update <%= item_path %>" do + put :update, id: @<%= item_path %>.to_param, <%= item_path %>: @<%= item_path %>.attributes + assert_redirected_to <%= item_path %>_path(assigns(:<%= item_path %>)) + end + + test "should destroy <%= item_path %>" do + assert_difference('<%= class_name %>.count', -1) do + delete :destroy, id: @<%= item_path %>.to_param + end + + assert_redirected_to <%= plural_name %>_path + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb new file mode 100644 index 0000000..09b835c --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= class_name %>Test < ActiveSupport::TestCase + def test_should_be_valid + assert <%= class_name %>.new.valid? + end +end diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml new file mode 100644 index 0000000..57cb828 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(<%= item_path :instance_variable => true %>) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('<%= plural_name %>.form.submit')
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml new file mode 100644 index 0000000..ca7f253 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs +<%- model_attributes.each do |attribute| -%> + = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>, :label => t('<%= plural_name %>.form.<%= attribute.name %>.label'), :hint => conditional_hint('<%= plural_name %>.form.<%= attribute.name %>.hint') +<%- end -%> diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml new file mode 100644 index 0000000..9cbea63 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml @@ -0,0 +1,13 @@ +%table + %tr + <%- for attribute in model_attributes -%> + %th= t('<%= plural_name %>.index.<%= attribute.name %>') + <%- end -%> + + - reset_cycle + - for <%= instance_name %> in <%= instances_name %> + %tr{:class => cycle('odd', 'even')} + <%- for attribute in model_attributes -%> + %td= <%= instance_name %>.<%= attribute.name %> + <%- end -%> + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => <%= instance_name %>}
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml new file mode 100644 index 0000000..dc7de62 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml @@ -0,0 +1,3 @@ +- title t("<%= plural_name %>.edit.page_title") + +<%= render_form %>
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml new file mode 100644 index 0000000..86c6b9e --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml @@ -0,0 +1,6 @@ +- title t("<%= plural_name %>.index.page_title") + +- if @<%= instances_name %> && @<%= instances_name %>.count > 0 + = render "index_core", :<%= instances_name %> => @<%= instances_name %> + += render :partial => 'shared/create_link', :locals => {:child_class => <%= instances_name.classify %>}
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml new file mode 100644 index 0000000..4e7f871 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml @@ -0,0 +1,3 @@ +- title t("<%= plural_name %>.new.page_title") + +<%= render_form %>
\ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml new file mode 100644 index 0000000..3d01340 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml @@ -0,0 +1,9 @@ +- title t("<%= plural_name %>.show.page_title") + +<%- for attribute in model_attributes -%> +%p + %strong= t('<%= plural_name %>.show.<%= attribute.name %>') + ":" + = @<%= instance_name %>.<%= attribute.name %> +<%- end -%> + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @<%= instance_name %> }
\ No newline at end of file |