diff options
20 files changed, 86 insertions, 83 deletions
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index cb109c6ad8..4bf8d90b69 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -431,7 +431,7 @@ module ActionController #:nodoc: The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the - best solution is to change your referrer policy to something less strict like same-origin or strict-same-origin. + best solution is to change your referrer policy to something less strict like same-origin or strict-origin. If you cannot change the referrer policy, you can disable origin checking with the Rails.application.config.action_controller.forgery_protection_origin_check setting. MSG diff --git a/actiontext/lib/action_text/attribute.rb b/actiontext/lib/action_text/attribute.rb index f226dd21bd..f9a604096c 100644 --- a/actiontext/lib/action_text/attribute.rb +++ b/actiontext/lib/action_text/attribute.rb @@ -34,14 +34,11 @@ module ActionText end CODE - has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: :destroy + has_one :"rich_text_#{name}", -> { where(name: name) }, + class_name: "ActionText::RichText", as: :record, inverse_of: :record, autosave: true, dependent: :destroy scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) } - - after_save do - public_send(name).save if public_send(name).changed? - end end end end diff --git a/actiontext/test/dummy/app/models/message.rb b/actiontext/test/dummy/app/models/message.rb index 9ea4dbfe78..7bce50753c 100644 --- a/actiontext/test/dummy/app/models/message.rb +++ b/actiontext/test/dummy/app/models/message.rb @@ -1,4 +1,7 @@ class Message < ApplicationRecord has_rich_text :content has_rich_text :body + + has_one :review + accepts_nested_attributes_for :review end diff --git a/actiontext/test/dummy/app/models/review.rb b/actiontext/test/dummy/app/models/review.rb new file mode 100644 index 0000000000..e54a37685d --- /dev/null +++ b/actiontext/test/dummy/app/models/review.rb @@ -0,0 +1,5 @@ +class Review < ApplicationRecord + belongs_to :message + + has_rich_text :content +end diff --git a/actiontext/test/dummy/db/migrate/20190317200724_create_reviews.rb b/actiontext/test/dummy/db/migrate/20190317200724_create_reviews.rb new file mode 100644 index 0000000000..96e0eab287 --- /dev/null +++ b/actiontext/test/dummy/db/migrate/20190317200724_create_reviews.rb @@ -0,0 +1,8 @@ +class CreateReviews < ActiveRecord::Migration[6.0] + def change + create_table :reviews do |t| + t.belongs_to :message, null: false + t.string :author_name, null: false + end + end +end diff --git a/actiontext/test/dummy/db/schema.rb b/actiontext/test/dummy/db/schema.rb index 60ccbd4873..03e99b29d2 100644 --- a/actiontext/test/dummy/db/schema.rb +++ b/actiontext/test/dummy/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_03_05_172303) do +ActiveRecord::Schema.define(version: 2019_03_17_200724) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false @@ -61,5 +61,11 @@ ActiveRecord::Schema.define(version: 2019_03_05_172303) do t.datetime "updated_at", precision: 6, null: false end + create_table "reviews", force: :cascade do |t| + t.integer "message_id", null: false + t.string "author_name", null: false + t.index ["message_id"], name: "index_reviews_on_message_id" + end + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" end diff --git a/actiontext/test/unit/model_test.rb b/actiontext/test/unit/model_test.rb index d56363adc0..f4328ba2ce 100644 --- a/actiontext/test/unit/model_test.rb +++ b/actiontext/test/unit/model_test.rb @@ -49,8 +49,22 @@ class ActionText::ModelTest < ActiveSupport::TestCase assert_equal "Hello world", message.content.to_plain_text end - test "save body" do + test "saving body" do message = Message.create(subject: "Greetings", body: "<h1>Hello world</h1>") assert_equal "Hello world", message.body.to_plain_text end + + test "saving content via nested attributes" do + message = Message.create! subject: "Greetings", content: "<h1>Hello world</h1>", + review_attributes: { author_name: "Marcia", content: "Nice work!" } + assert_equal "Nice work!", message.review.content.to_plain_text + end + + test "updating content via nested attributes" do + message = Message.create! subject: "Greetings", content: "<h1>Hello world</h1>", + review_attributes: { author_name: "Marcia", content: "Nice work!" } + + message.update! review_attributes: { id: message.review.id, content: "Great work!" } + assert_equal "Great work!", message.review.reload.content.to_plain_text + end end diff --git a/activerecord/lib/arel/insert_manager.rb b/activerecord/lib/arel/insert_manager.rb index c90fc33a48..cb31e3060b 100644 --- a/activerecord/lib/arel/insert_manager.rb +++ b/activerecord/lib/arel/insert_manager.rb @@ -33,13 +33,13 @@ module Arel # :nodoc: all @ast.columns << column values << value end - @ast.values = create_values values, @ast.columns + @ast.values = create_values(values) end self end - def create_values(values, columns) - Nodes::Values.new values, columns + def create_values(values) + Nodes::ValuesList.new([values]) end def create_values_list(rows) diff --git a/activerecord/lib/arel/nodes.rb b/activerecord/lib/arel/nodes.rb index 5af0e532e2..2f6dd9bc45 100644 --- a/activerecord/lib/arel/nodes.rb +++ b/activerecord/lib/arel/nodes.rb @@ -45,7 +45,6 @@ require "arel/nodes/and" require "arel/nodes/function" require "arel/nodes/count" require "arel/nodes/extract" -require "arel/nodes/values" require "arel/nodes/values_list" require "arel/nodes/named_function" diff --git a/activerecord/lib/arel/nodes/values.rb b/activerecord/lib/arel/nodes/values.rb deleted file mode 100644 index 650248dc04..0000000000 --- a/activerecord/lib/arel/nodes/values.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module Arel # :nodoc: all - module Nodes - class Values < Arel::Nodes::Binary - alias :expressions :left - alias :expressions= :left= - alias :columns :right - alias :columns= :right= - - def initialize(exprs, columns = []) - super - end - end - end -end diff --git a/activerecord/lib/arel/nodes/values_list.rb b/activerecord/lib/arel/nodes/values_list.rb index 27109848e4..1a9d9ebf01 100644 --- a/activerecord/lib/arel/nodes/values_list.rb +++ b/activerecord/lib/arel/nodes/values_list.rb @@ -2,23 +2,8 @@ module Arel # :nodoc: all module Nodes - class ValuesList < Node - attr_reader :rows - - def initialize(rows) - @rows = rows - super() - end - - def hash - @rows.hash - end - - def eql?(other) - self.class == other.class && - self.rows == other.rows - end - alias :== :eql? + class ValuesList < Unary + alias :rows :expr end end end diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb index 892d670c79..109afb7402 100644 --- a/activerecord/lib/arel/visitors/depth_first.rb +++ b/activerecord/lib/arel/visitors/depth_first.rb @@ -36,6 +36,7 @@ module Arel # :nodoc: all alias :visit_Arel_Nodes_Descending :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary alias :visit_Arel_Nodes_OptimizerHints :unary + alias :visit_Arel_Nodes_ValuesList :unary def function(o) visit o.expressions @@ -103,7 +104,6 @@ module Arel # :nodoc: all alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary - alias :visit_Arel_Nodes_Values :binary alias :visit_Arel_Nodes_When :binary def visit_Arel_Nodes_StringJoin(o) diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb index ffcbb7a7ab..37803ce0c0 100644 --- a/activerecord/lib/arel/visitors/dot.rb +++ b/activerecord/lib/arel/visitors/dot.rb @@ -46,8 +46,8 @@ module Arel # :nodoc: all visit_edge o, "distinct" end - def visit_Arel_Nodes_Values(o) - visit_edge o, "expressions" + def visit_Arel_Nodes_ValuesList(o) + visit_edge o, "rows" end def visit_Arel_Nodes_StringJoin(o) diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 7e3e265208..583f920290 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -159,7 +159,7 @@ module Arel # :nodoc: all when Nodes::SqlLiteral, Nodes::BindParam collector = visit(value, collector) else - collector << quote(value) + collector << quote(value).to_s end collector << COMMA unless k == row_len end @@ -169,25 +169,6 @@ module Arel # :nodoc: all collector end - def visit_Arel_Nodes_Values(o, collector) - collector << "VALUES (" - - len = o.expressions.length - 1 - o.expressions.each_with_index { |value, i| - case value - when Nodes::SqlLiteral, Nodes::BindParam - collector = visit value, collector - else - collector << quote(value).to_s - end - unless i == len - collector << COMMA - end - } - - collector << ")" - end - def visit_Arel_Nodes_SelectStatement(o, collector) if o.with collector = visit o.with, collector @@ -805,7 +786,9 @@ module Arel # :nodoc: all end def sanitize_as_sql_comment(o) - o.expr.map { |v| v.gsub(%r{ /\*\+?\s* | \s*\*/ }x, "") } + o.expr.map { |v| + v.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "") + } end def collect_optimizer_hints(o, collector) diff --git a/activerecord/test/cases/adapters/mysql2/optimizer_hints_test.rb b/activerecord/test/cases/adapters/mysql2/optimizer_hints_test.rb index 31a002e935..b9794c5710 100644 --- a/activerecord/test/cases/adapters/mysql2/optimizer_hints_test.rb +++ b/activerecord/test/cases/adapters/mysql2/optimizer_hints_test.rb @@ -13,13 +13,23 @@ if supports_optimizer_hints? posts = posts.select(:id).where(author_id: [0, 1]) assert_includes posts.explain, "| index | index_posts_on_author_id | index_posts_on_author_id |" end + end + def test_optimizer_hints_is_sanitized assert_sql(%r{\ASELECT /\*\+ NO_RANGE_OPTIMIZATION\(posts index_posts_on_author_id\) \*/}) do posts = Post.optimizer_hints("/*+ NO_RANGE_OPTIMIZATION(posts index_posts_on_author_id) */") posts = posts.select(:id).where(author_id: [0, 1]) assert_includes posts.explain, "| index | index_posts_on_author_id | index_posts_on_author_id |" end + assert_sql(%r{\ASELECT /\*\+ `posts`\.\*, \*/}) do + posts = Post.optimizer_hints("**// `posts`.*, //**") + posts = posts.select(:id).where(author_id: [0, 1]) + assert_equal({ "id" => 1 }, posts.first.as_json) + end + end + + def test_optimizer_hints_with_unscope assert_sql(%r{\ASELECT `posts`\.`id`}) do posts = Post.optimizer_hints("/*+ NO_RANGE_OPTIMIZATION(posts index_posts_on_author_id) */") posts = posts.select(:id).where(author_id: [0, 1]) diff --git a/activerecord/test/cases/adapters/postgresql/optimizer_hints_test.rb b/activerecord/test/cases/adapters/postgresql/optimizer_hints_test.rb index 4fac7ffdc0..5e4bf232e1 100644 --- a/activerecord/test/cases/adapters/postgresql/optimizer_hints_test.rb +++ b/activerecord/test/cases/adapters/postgresql/optimizer_hints_test.rb @@ -17,13 +17,23 @@ if supports_optimizer_hints? posts = posts.select(:id).where(author_id: [0, 1]) assert_includes posts.explain, "Seq Scan on posts" end + end + def test_optimizer_hints_is_sanitized assert_sql(%r{\ASELECT /\*\+ SeqScan\(posts\) \*/}) do posts = Post.optimizer_hints("/*+ SeqScan(posts) */") posts = posts.select(:id).where(author_id: [0, 1]) assert_includes posts.explain, "Seq Scan on posts" end + assert_sql(%r{\ASELECT /\*\+ "posts"\.\*, \*/}) do + posts = Post.optimizer_hints("**// \"posts\".*, //**") + posts = posts.select(:id).where(author_id: [0, 1]) + assert_equal({ "id" => 1 }, posts.first.as_json) + end + end + + def test_optimizer_hints_with_unscope assert_sql(%r{\ASELECT "posts"\."id"}) do posts = Post.optimizer_hints("/*+ SeqScan(posts) */") posts = posts.select(:id).where(author_id: [0, 1]) diff --git a/activerecord/test/cases/arel/insert_manager_test.rb b/activerecord/test/cases/arel/insert_manager_test.rb index 2376ad8d37..79b85742ee 100644 --- a/activerecord/test/cases/arel/insert_manager_test.rb +++ b/activerecord/test/cases/arel/insert_manager_test.rb @@ -11,19 +11,18 @@ module Arel end describe "insert" do - it "can create a Values node" do + it "can create a ValuesList node" do manager = Arel::InsertManager.new - values = manager.create_values %w{ a b }, %w{ c d } + values = manager.create_values_list([%w{ a b }, %w{ c d }]) - assert_kind_of Arel::Nodes::Values, values - assert_equal %w{ a b }, values.left - assert_equal %w{ c d }, values.right + assert_kind_of Arel::Nodes::ValuesList, values + assert_equal [%w{ a b }, %w{ c d }], values.rows end it "allows sql literals" do manager = Arel::InsertManager.new manager.into Table.new(:users) - manager.values = manager.create_values [Arel.sql("*")], %w{ a } + manager.values = manager.create_values([Arel.sql("*")]) manager.to_sql.must_be_like %{ INSERT INTO \"users\" VALUES (*) } @@ -186,9 +185,9 @@ module Arel manager = Arel::InsertManager.new manager.into table - manager.values = Nodes::Values.new [1] + manager.values = Nodes::ValuesList.new([[1], [2]]) manager.to_sql.must_be_like %{ - INSERT INTO "users" VALUES (1) + INSERT INTO "users" VALUES (1), (2) } end @@ -210,11 +209,11 @@ module Arel manager = Arel::InsertManager.new manager.into table - manager.values = Nodes::Values.new [1, "aaron"] + manager.values = Nodes::ValuesList.new([[1, "aaron"], [2, "david"]]) manager.columns << table[:id] manager.columns << table[:name] manager.to_sql.must_be_like %{ - INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron'), (2, 'david') } end end diff --git a/activerecord/test/cases/arel/visitors/depth_first_test.rb b/activerecord/test/cases/arel/visitors/depth_first_test.rb index f94ad521d7..4a57608411 100644 --- a/activerecord/test/cases/arel/visitors/depth_first_test.rb +++ b/activerecord/test/cases/arel/visitors/depth_first_test.rb @@ -33,6 +33,7 @@ module Arel Arel::Nodes::Ordering, Arel::Nodes::StringJoin, Arel::Nodes::UnqualifiedColumn, + Arel::Nodes::ValuesList, Arel::Nodes::Limit, Arel::Nodes::Else, ].each do |klass| @@ -116,7 +117,6 @@ module Arel Arel::Nodes::NotIn, Arel::Nodes::Or, Arel::Nodes::TableAlias, - Arel::Nodes::Values, Arel::Nodes::As, Arel::Nodes::DeleteStatement, Arel::Nodes::JoinSource, diff --git a/activerecord/test/cases/arel/visitors/dot_test.rb b/activerecord/test/cases/arel/visitors/dot_test.rb index 6b3c132f83..ade53c358e 100644 --- a/activerecord/test/cases/arel/visitors/dot_test.rb +++ b/activerecord/test/cases/arel/visitors/dot_test.rb @@ -37,6 +37,7 @@ module Arel Arel::Nodes::Offset, Arel::Nodes::Ordering, Arel::Nodes::UnqualifiedColumn, + Arel::Nodes::ValuesList, Arel::Nodes::Limit, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do @@ -61,7 +62,6 @@ module Arel Arel::Nodes::NotIn, Arel::Nodes::Or, Arel::Nodes::TableAlias, - Arel::Nodes::Values, Arel::Nodes::As, Arel::Nodes::DeleteStatement, Arel::Nodes::JoinSource, diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb index 4bfa799a96..625e37f1c0 100644 --- a/activerecord/test/cases/arel/visitors/to_sql_test.rb +++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb @@ -23,9 +23,9 @@ module Arel sql.must_be_like "?" end - it "does not quote BindParams used as part of a Values" do + it "does not quote BindParams used as part of a ValuesList" do bp = Nodes::BindParam.new(1) - values = Nodes::Values.new([bp]) + values = Nodes::ValuesList.new([[bp]]) sql = compile values sql.must_be_like "VALUES (?)" end |