diff options
21 files changed, 172 insertions, 30 deletions
@@ -19,7 +19,6 @@ gem "jquery-rails" gem "coffee-rails" gem "sass-rails" gem "turbolinks", "~> 5" -gem "rails-ujs", github: "rails/rails-ujs" # require: false so bcrypt is loaded only when has_secure_password is used. # This is to avoid Active Model (and by extension the entire framework) @@ -39,6 +38,8 @@ gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", requi # Explicitly avoid 1.x that doesn't support Ruby 2.4+ gem "json", ">= 2.0.0" +gem "rubocop", require: false + group :doc do gem "sdoc", "1.0.0.beta2" gem "redcarpet", "~> 3.2.3", platforms: :ruby diff --git a/Gemfile.lock b/Gemfile.lock index bc88ca95bc..eb14330c2b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,13 +39,6 @@ GIT websocket GIT - remote: https://github.com/rails/rails-ujs.git - revision: 767692f53dec79d42928029a55fdfcced35681e8 - specs: - rails-ujs (0.0.1) - railties (>= 3.1) - -GIT remote: https://github.com/resque/resque.git revision: 20d885065ac19e7f7d7a982f4ed1296083db0300 specs: @@ -129,6 +122,7 @@ GEM public_suffix (~> 2.0, >= 2.0.2) amq-protocol (2.0.1) arel (7.1.2) + ast (2.3.0) backburner (1.3.1) beaneater (~> 1.0) concurrent-ruby (~> 1.0.1) @@ -254,9 +248,12 @@ GEM mini_portile2 (~> 2.1.0) nokogiri (1.6.8.1-x86-mingw32) mini_portile2 (~> 2.1.0) + parser (2.3.2.0) + ast (~> 2.2) pg (0.19.0) pg (0.19.0-x64-mingw32) pg (0.19.0-x86-mingw32) + powerpack (0.1.1) psych (2.1.1) public_suffix (2.0.4) puma (3.6.0) @@ -280,6 +277,7 @@ GEM nokogiri (~> 1.6.0) rails-html-sanitizer (1.0.3) loofah (~> 2.0) + rainbow (2.1.0) rake (11.3.0) rb-fsevent (0.9.7) rdoc (5.0.0.beta2) @@ -292,6 +290,13 @@ GEM redis (~> 3.3) resque (~> 1.26) rufus-scheduler (~> 3.2) + rubocop (0.45.0) + parser (>= 2.3.1.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.8.1) ruby_dep (1.4.0) rubyzip (1.2.0) rufus-scheduler (3.2.2) @@ -355,6 +360,7 @@ GEM tzinfo (>= 1.0.0) uglifier (3.0.2) execjs (>= 0.3.0, < 3) + unicode-display_width (1.1.1) useragent (0.16.8) vegas (0.1.11) rack (>= 1.0.0) @@ -406,13 +412,13 @@ DEPENDENCIES racc (>= 1.4.6) rack-cache (~> 1.2) rails! - rails-ujs! rake (>= 11.1) rb-inotify! redcarpet (~> 3.2.3) redis resque! resque-scheduler + rubocop sass! sass-rails sdoc (= 1.0.0.beta2) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index b74c5d3e83..1ab6158c90 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -577,7 +577,8 @@ module ActionDispatch # end # end # - # The +as+ option sets the format to JSON, sets the content type to + # The +as+ option passes an "application/json" Accept header (thereby setting + # the request format to JSON unless overridden), sets the content type to # "application/json" and encodes the parameters as JSON. # # Calling +parsed_body+ on the response parses the response body based on the diff --git a/actionpack/lib/action_dispatch/testing/request_encoder.rb b/actionpack/lib/action_dispatch/testing/request_encoder.rb index 734fc8cb54..8c27e9ecb7 100644 --- a/actionpack/lib/action_dispatch/testing/request_encoder.rb +++ b/actionpack/lib/action_dispatch/testing/request_encoder.rb @@ -11,7 +11,7 @@ module ActionDispatch attr_reader :response_parser - def initialize(mime_name, param_encoder, response_parser = nil) + def initialize(mime_name, param_encoder, response_parser) @mime = Mime[mime_name] unless @mime diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index d8be5d32e1..d3aa81a0f7 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -145,7 +145,7 @@ class IntegrationTestTest < ActiveSupport::TestCase name.to_s == "foo" ? "pass" : super end end - @test.class.superclass.__send__(:include, mixin) + @test.class.superclass.include(mixin) begin assert_equal "pass", @test.foo ensure diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 6f602e4a23..4e941cf2df 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -373,7 +373,7 @@ module ActiveRecord stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates)) stmt.table(table) - if joins_values.any? + if has_join_values? @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key)) else stmt.key = arel_attribute(primary_key) @@ -522,7 +522,7 @@ module ActiveRecord stmt = Arel::DeleteManager.new stmt.from(table) - if joins_values.any? + if has_join_values? @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key)) else stmt.wheres = arel.constraints @@ -680,6 +680,10 @@ module ActiveRecord private + def has_join_values? + joins_values.any? || left_outer_joins_values.any? + end + def exec_queries(&block) @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index f667e9b055..3f1da82cb4 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -90,6 +90,14 @@ class PersistenceTest < ActiveRecord::TestCase assert_equal count, Pet.joins(:toys).where(where_args).delete_all end + def test_delete_all_with_left_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, 1 + assert_equal count, Pet.left_joins(:toys).where(where_args).delete_all + end + def test_delete_all_with_joins_and_where_part_is_not_hash where_args = ["toys.name = ?", "Bone"] count = Pet.joins(:toys).where(where_args).count @@ -453,6 +461,20 @@ class PersistenceTest < ActiveRecord::TestCase assert_nil Topic.find(2).last_read end + def test_update_all_with_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, Pet.joins(:toys).where(where_args).update_all(name: "Bob") + end + + def test_update_all_with_left_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, Pet.left_joins(:toys).where(where_args).update_all(name: "Bob") + end + def test_update_all_with_non_standard_table_name assert_equal 1, WarehouseThing.where(id: 1).update_all(["value = ?", 0]) assert_equal 0, WarehouseThing.find(1).value diff --git a/activerecord/test/cases/test_fixtures_test.rb b/activerecord/test/cases/test_fixtures_test.rb index 14a5faa85e..7090202a89 100644 --- a/activerecord/test/cases/test_fixtures_test.rb +++ b/activerecord/test/cases/test_fixtures_test.rb @@ -3,7 +3,7 @@ require "cases/helper" class TestFixturesTest < ActiveRecord::TestCase setup do @klass = Class.new - @klass.send(:include, ActiveRecord::TestFixtures) + @klass.include(ActiveRecord::TestFixtures) end def test_deprecated_use_transactional_fixtures= diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 95507c815d..7a5a5414a7 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -76,7 +76,7 @@ class ConcernTest < ActiveSupport::TestCase end def test_class_methods_are_extended_only_on_expected_objects - ::Object.__send__(:include, Qux) + ::Object.include(Qux) Object.extend(Qux::ClassMethods) # module needs to be created after Qux is included in Object or bug won't # be triggered diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index c04d42d743..6ec5106bb3 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -1157,7 +1157,7 @@ it look as follows: ```html+erb <h1>Edit article</h1> -<%= form_for :article, url: article_path(@article), method: :patch do |f| %> +<%= form_for(@article) do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> @@ -1195,14 +1195,15 @@ it look as follows: This time we point the form to the `update` action, which is not defined yet but will be very soon. -The `method: :patch` option tells Rails that we want this form to be submitted +Passing the article object to the method, will automagically create url for submitting the edited article form. +This option tells Rails that we want this form to be submitted via the `PATCH` HTTP method which is the HTTP method you're expected to use to **update** resources according to the REST protocol. The first parameter of `form_for` can be an object, say, `@article` which would cause the helper to fill in the form with the fields of the object. Passing in a symbol (`:article`) with the same name as the instance variable (`@article`) -also automagically leads to the same behavior. This is what is happening here. +also automagically leads to the same behavior. More details can be found in [form_for documentation] (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for). diff --git a/guides/source/testing.md b/guides/source/testing.md index bc1f78fb2a..29a9537141 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -800,6 +800,13 @@ end Now you can try running all the tests and they should pass. +NOTE: If you followed the steps in the Basic Authentication section, you'll need to add the following to the `setup` block to get all the tests passing: + +```ruby +request.headers['Authorization'] = ActionController::HttpAuthentication::Basic. + encode_credentials('dhh', 'secret') +``` + ### Available Request Types for Functional Tests If you're familiar with the HTTP protocol, you'll know that `get` is a type of request. There are 6 request types supported in Rails functional tests: diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 5e5583734a..819d760433 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,10 @@ -* Removed jquery-rails from default stack, instead rails-ujs is - included as default UJS adapter. +* Add Yarn support in new apps using --yarn option. This add a package.json + and the settings needed to get npm modules integrated in new apps. + + *Liceth Ovalles*, *Guillermo Iguaran* + +* Removed jquery-rails from default stack, instead rails-ujs that is shipped + with Action View is included as default UJS adapter. *Guillermo Iguaran* diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 2951d6c83d..99fc5d9525 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -33,6 +33,9 @@ module Rails class_option :javascript, type: :string, aliases: "-j", desc: "Preconfigure for selected JavaScript library" + class_option :yarn, type: :boolean, default: false, + desc: "Preconfigure for assets management with Yarn" + class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" @@ -333,9 +336,6 @@ module Rails "Use #{options[:javascript]} as the JavaScript library") end - gems << GemfileEntry.github("rails-ujs", "rails/rails-ujs", nil, - "Unobstrusive JavaScript adapter for Rails") - unless options[:skip_turbolinks] gems << GemfileEntry.version("turbolinks", "~> 5", "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") @@ -414,6 +414,55 @@ module Rails bundle_command("install") if bundle_install? end + def run_yarn + if package_json_exist? + if yarn_path + say_status :run, "yarn install" + yarn_command("install") + else + say_status :warning, "yarn option passed but Yarn executable was not detected in the system.", :yellow + say_status :warning, "Download Yarn at https://yarnpkg.com/en/docs/install", :yellow + end + end + end + + def package_json_exist? + File.exist?("package.json") + end + + def yarn_path + commands = ["yarn"] + + if RbConfig::CONFIG["host_os"] =~ /mswin|cygwin/ + ENV["PATHEXT"].split(File::PATH_SEPARATOR).each do |ext| + commands << commands[0] + ext + end + end + + yarn_path = commands.find do |cmd| + paths = ENV["PATH"].split(File::PATH_SEPARATOR) + + path = paths.find do |p| + full_path = File.expand_path(cmd, p) + File.executable?(full_path) && File.file?(full_path) + end + + path && File.expand_path(cmd, path) + end + + yarn_path + end + + def yarn_command(command) + full_command = "#{yarn_path} #{command}" + + if options[:quiet] + system(full_command, out: File::NULL) + else + system(full_command) + end + end + def generate_spring_binstubs if bundle_install? && spring_install? bundle_command("exec spring binstub --all") diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index d6ffa2d89d..03fd298fbc 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -53,6 +53,10 @@ module Rails template "gitignore", ".gitignore" end + def packagejson + template "package.json" + end + def app directory "app" @@ -205,6 +209,7 @@ module Rails build(:readme) build(:rakefile) build(:configru) + build(:packagejson) if options[:yarn] build(:gitignore) unless options[:skip_git] build(:gemfile) unless options[:skip_gemfile] end @@ -355,7 +360,7 @@ module Rails end public_task :apply_rails_template, :run_bundle - public_task :generate_spring_binstubs + public_task :run_yarn, :generate_spring_binstubs def run_after_bundle_callbacks @after_bundle_callbacks.each(&:call) diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup.tt b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt index 8635e97b76..c82a922eef 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup.tt +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt @@ -16,8 +16,11 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') -<% unless options.skip_active_record -%> +<% if options[:yarn] %> + system! 'yarn' +<% end %> +<% unless options.skip_active_record -%> # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') # cp 'config/database.yml.sample', 'config/database.yml' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update.tt b/railties/lib/rails/generators/rails/app/templates/bin/update.tt index d385b363c6..0d8ca2f902 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/update.tt +++ b/railties/lib/rails/generators/rails/app/templates/bin/update.tt @@ -16,8 +16,11 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') -<% unless options.skip_active_record -%> +<% if options[:yarn] %> + system! 'yarn' +<% end %> +<% unless options.skip_active_record -%> puts "\n== Updating database ==" system! 'bin/rails db:migrate' <% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt index 2318cf59ff..1ba182e562 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt @@ -5,6 +5,10 @@ Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path # Rails.application.config.assets.paths << Emoji.images_path +<%- if options[:yarn] -%> +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') +<%- end -%> # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 0e66cc4237..bdcbe8d629 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -21,5 +21,10 @@ !/tmp/.keep <% end -%> +<% if options[:yarn] -%> +# Ignore node modules. +/node_modules/* + +<% end -%> # Ignore Byebug command history file. .byebug_history diff --git a/railties/lib/rails/generators/rails/app/templates/package.json b/railties/lib/rails/generators/rails/app/templates/package.json new file mode 100644 index 0000000000..46db57dcbe --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/package.json @@ -0,0 +1,5 @@ +{ + "name": "<%= app_name %>", + "private": true, + "dependencies": {} +} diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index cefad48f52..7069a07bbe 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -35,7 +35,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_no_match(/gem 'coffee-rails'/, content) - assert_no_match(/gem 'rails-ujs'/, content) assert_no_match(/gem 'sass-rails'/, content) assert_no_match(/gem 'web-console'/, content) assert_match(/# gem 'jbuilder'/, content) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 2d01da7f46..0f73c43e0c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -452,7 +452,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "app/assets/javascripts/application.js" do |contents| assert_match %r{^//= require rails-ujs}, contents end - assert_gem "rails-ujs" end def test_inclusion_of_javascript_libraries_if_required @@ -477,7 +476,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_no_match(/coffee-rails/, content) assert_no_match(/uglifier/, content) - assert_no_match(/rails-ujs/, content) end assert_file "config/environments/production.rb" do |content| @@ -494,6 +492,12 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generator_if_yarn_option_is_given + run_generator([destination_root, "--yarn"]) + assert_file "package.json", /dependencies/ + assert_file "config/initializers/assets.rb", /node_modules/ + end + def test_inclusion_of_jbuilder run_generator assert_gem "jbuilder" @@ -614,6 +618,10 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_generates_with_bundler end + def test_generation_runs_yarn_install_with_yarn_option + assert_generates_with_yarn yarn: true + end + def test_dev_option assert_generates_with_bundler dev: true rails_path = File.expand_path("../../..", Rails.root) @@ -839,4 +847,18 @@ class AppGeneratorTest < Rails::Generators::TestCase quietly { generator.invoke_all } end end + + def assert_generates_with_yarn(options = {}) + generator([destination_root], options) + + command_check = -> command do + @install_called ||= 0 + @install_called += 1 + assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times" + end + + generator.stub :yarn_command, command_check do + quietly { generator.invoke_all } + end + end end |