{"action":"created","issue":{"url":"https://api.github.com/repos/rails/rails/issues/21488","labels_url":"https://api.github.com/repos/rails/rails/issues/21488/labels{/name}","comments_url":"https://api.github.com/repos/rails/rails/issues/21488/comments","events_url":"https://api.github.com/repos/rails/rails/issues/21488/events","html_url":"https://github.com/rails/rails/issues/21488","id":104705648,"number":21488,"title":"ActiveRecord::QueryMethods#from no longer escapes mysql attributes when using #alias_attribute","user":{"login":"johanlunds","id":22144,"avatar_url":"https://avatars.githubusercontent.com/u/22144?v=3","gravatar_id":"","url":"https://api.github.com/users/johanlunds","html_url":"https://github.com/johanlunds","followers_url":"https://api.github.com/users/johanlunds/followers","following_url":"https://api.github.com/users/johanlunds/following{/other_user}","gists_url":"https://api.github.com/users/johanlunds/gists{/gist_id}","starred_url":"https://api.github.com/users/johanlunds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johanlunds/subscriptions","organizations_url":"https://api.github.com/users/johanlunds/orgs","repos_url":"https://api.github.com/users/johanlunds/repos","events_url":"https://api.github.com/users/johanlunds/events{/privacy}","received_events_url":"https://api.github.com/users/johanlunds/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rails/rails/labels/activerecord","name":"activerecord","color":"0b02e1"}],"state":"closed","locked":false,"assignee":{"login":"sgrif","id":1529387,"avatar_url":"https://avatars.githubusercontent.com/u/1529387?v=3","gravatar_id":"","url":"https://api.github.com/users/sgrif","html_url":"https://github.com/sgrif","followers_url":"https://api.github.com/users/sgrif/followers","following_url":"https://api.github.com/users/sgrif/following{/other_user}","gists_url":"https://api.github.com/users/sgrif/gists{/gist_id}","starred_url":"https://api.github.com/users/sgrif/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sgrif/subscriptions","organizations_url":"https://api.github.com/users/sgrif/orgs","repos_url":"https://api.github.com/users/sgrif/repos","events_url":"https://api.github.com/users/sgrif/events{/privacy}","received_events_url":"https://api.github.com/users/sgrif/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/rails/rails/milestones/44","html_url":"https://github.com/rails/rails/milestones/4.2.5","labels_url":"https://api.github.com/repos/rails/rails/milestones/44/labels","id":1254218,"number":44,"title":"4.2.5","description":"","creator":{"login":"rafaelfranca","id":47848,"avatar_url":"https://avatars.githubusercontent.com/u/47848?v=3","gravatar_id":"","url":"https://api.github.com/users/rafaelfranca","html_url":"https://github.com/rafaelfranca","followers_url":"https://api.github.com/users/rafaelfranca/followers","following_url":"https://api.github.com/users/rafaelfranca/following{/other_user}","gists_url":"https://api.github.com/users/rafaelfranca/gists{/gist_id}","starred_url":"https://api.github.com/users/rafaelfranca/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rafaelfranca/subscriptions","organizations_url":"https://api.github.com/users/rafaelfranca/orgs","repos_url":"https://api.github.com/users/rafaelfranca/repos","events_url":"https://api.github.com/users/rafaelfranca/events{/privacy}","received_events_url":"https://api.github.com/users/rafaelfranca/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":1,"state":"open","created_at":"2015-08-13T20:20:11Z","updated_at":"2015-09-21T17:16:24Z","due_on":"2015-09-24T03:00:00Z","closed_at":null},"comments":3,"created_at":"2015-09-03T14:19:30Z","updated_at":"2015-09-21T17:17:19Z","closed_at":"2015-09-21T17:16:24Z","body":"This is the same as https://github.com/rails/rails/issues/20360, but for a special case of that issue.\r\n\r\nThe special case: when using `#alias_attribute` in model it generates the same, invalid query as in previously reported (and fixed) issue.\r\n\r\n## Script to reproduce\r\n\r\n```ruby\r\nunless File.exist?('Gemfile')\r\n  File.write('Gemfile', <<-GEMFILE)\r\n    source 'https://rubygems.org'\r\n    gem 'rails', '4.2.4' # works with '4.2.0'\r\n    gem 'mysql2'\r\n  GEMFILE\r\n\r\n  system 'bundle'\r\nend\r\n\r\nrequire 'bundler'\r\nBundler.setup(:default)\r\n\r\nrequire 'active_record'\r\nrequire 'minitest/autorun'\r\nrequire 'logger'\r\n\r\n# This connection will do for database-independent bug reports.\r\nActiveRecord::Base.establish_connection(adapter: 'mysql2',\r\n                                        host: 'localhost',\r\n                                        username: 'root',\r\n                                        password: '',\r\n                                        database: 'rails_mysql_bug_test')\r\nActiveRecord::Base.logger = Logger.new(STDOUT)\r\n\r\nActiveRecord::Schema.define do\r\n  create_table :test, force: true  do |t|\r\n    t.integer :desc\r\n  end\r\nend\r\n\r\nclass Test < ActiveRecord::Base\r\n  self.table_name = :test\r\n\r\n  alias_attribute :description, :desc\r\n\r\n  # NOTE: that we select the aliased name here, ie. \"description\" and not \"desc\"\r\n  default_scope { select(:description) }\r\nend\r\n\r\nclass BugTest < Minitest::Test\r\n  def test_from_escaping_attributes\r\n    Test.create!(desc: 10)\r\n    Test.create!(desc: 11)\r\n\r\n    result = Test.from(Test.where(desc: 10), Test.table_name)\r\n\r\n    assert_equal 1, result.to_a.size\r\n  end\r\nend\r\n```\r\n\r\n## Diff of script in previously, reported issue\r\n\r\n```diff\r\n35c35,39\r\n<   default_scope { select(:desc) }\r\n---\r\n>   alias_attribute :description, :desc\r\n>\r\n>   # NOTE: that we select the aliased name here, ie. \"description\" and not \"desc\"\r\n>   default_scope { select(:description) }\r\n```\r\n\r\n## Rails 4.2.0\r\n\r\nGenerates query:\r\n\r\n```sql\r\nSELECT `test`.`desc` FROM (SELECT `test`.`desc` FROM `test` WHERE `test`.`desc` = 10) test\r\n```\r\n\r\n## Rails 4.2.4\r\n\r\nGenerates query:\r\n\r\n```sql\r\nSELECT desc FROM (SELECT `test`.`desc` FROM `test` WHERE `test`.`desc` = 10) test\r\n```\r\n\r\nOnce again `desc` is not escaped, which causes a syntax error in Mysql:\r\n\r\n```\r\nMysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc FROM (SELECT `test`.`desc` FROM `test` WHERE `test`.`desc` = 10) test' at line 1: SELECT desc FROM (SELECT `test`.`desc` FROM `test` WHERE `test`.`desc` = 10) test\r\n```\r\n\r\n## Investigation to root cause/what happens\r\n\r\n1. Calling `#alias_attribute` will set `self.attribute_aliases = { 'description' => 'desc' }`. [Source](https://github.com/rails/rails/blob/20f60f276fe3d455b2a9b9fdd1f902fd00f3558e/activemodel/lib/active_model/attribute_methods.rb#L209). Note that both key and value are strings.\r\n2. Execute `#from`\r\n  1. Which generates a default scope by executing the block in `#default_scope`\r\n    1. Which executes `#select` and sets `@values[:select] = ['desc']`. Note that the array contains a string. This is because the call to `#attribute_alias` returns a string. [Source](https://github.com/rails/rails/blob/b9af060569907ce83a2680aff0718e8bad310345/activerecord/lib/active_record/relation/query_methods.rb#L261).\r\n3. Execute `#to_a` (ie. execute query) on the relation which will call `#build_arel`\r\n  1. `#arel_columns` won't escape the column name because `@values[:select]` contains a string `'desc'`. [Source](https://github.com/rails/rails/blob/b9af060569907ce83a2680aff0718e8bad310345/activerecord/lib/active_record/relation/query_methods.rb#L1067)\r\n\r\n## Suggested fix\r\n\r\nChange `klass.attribute_alias(field)` to `klass.attribute_alias(field).to_sym` in `#select`. [Source](https://github.com/rails/rails/blob/b9af060569907ce83a2680aff0718e8bad310345/activerecord/lib/active_record/relation/query_methods.rb#L261)\r\n\r\n## Temporary workaround\r\n\r\nWe changed this code:\r\n\r\n```ruby\r\ndefault_scope { select(:description) }\r\n```\r\n\r\nTo this in our app:\r\n\r\n```ruby\r\ndefault_scope { select(:desc) }\r\n```"},"comment":{"url":"https://api.github.com/repos/rails/rails/issues/comments/142047188","html_url":"https://github.com/rails/rails/issues/21488#issuecomment-142047188","issue_url":"https://api.github.com/repos/rails/rails/issues/21488","id":142047188,"user":{"login":"sgrif","id":1529387,"avatar_url":"https://avatars.githubusercontent.com/u/1529387?v=3","gravatar_id":"","url":"https://api.github.com/users/sgrif","html_url":"https://github.com/sgrif","followers_url":"https://api.github.com/users/sgrif/followers","following_url":"https://api.github.com/users/sgrif/following{/other_user}","gists_url":"https://api.github.com/users/sgrif/gists{/gist_id}","starred_url":"https://api.github.com/users/sgrif/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sgrif/subscriptions","organizations_url":"https://api.github.com/users/sgrif/orgs","repos_url":"https://api.github.com/users/sgrif/repos","events_url":"https://api.github.com/users/sgrif/events{/privacy}","received_events_url":"https://api.github.com/users/sgrif/received_events","type":"User","site_admin":false},"created_at":"2015-09-21T17:17:19Z","updated_at":"2015-09-21T17:17:19Z","body":"(Ultimately this change is still lacking, but the \"correct\" solution requires better hooks into our aliasing behavior, which I'm planning on doing in the future, but is impossible today)"}}