aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relation
Commit message (Collapse)AuthorAgeFilesLines
* docs, get rid of artifact in `RecordFetchWarning` docs.Yves Senn2015-11-071-0/+2
| | | | | | | [ci skip] There was a `ActiveRecord::Relation::RecordFetchWarning::ActiveSupport` artifact caused by subscribing to AS notifications.
* Define `sanitize_sql_for_order` for AR and use it inside `preprocess_order_args`yui-knk2015-11-021-5/+1
| | | | This commit follows up of 6a6dbb4c51fb0c58ba1a810eaa552774167b758a.
* Alias left_joins to left_outer_joinsTakashi Kokubun2015-10-311-0/+2
|
* Merge pull request #12071 from Crunch09/outer_joinsSean Griffin2015-10-301-1/+39
|\ | | | | | | added ActiveRecord::Relation#outer_joins
| * added ActiveRecord::Relation#left_outer_joinsFlorian Thomas2015-05-191-1/+39
| | | | | | | | | | | | Example: User.left_outer_joins(:posts) => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
* | Merge pull request #13008 from ktheory/sanitize_orderSean Griffin2015-10-291-0/+7
|\ \ | | | | | | | | | Support SQL sanitization in AR::QueryMethods#order
| * | Support SQL sanitization in AR::QueryMethods#orderAaron Suggs2013-11-221-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add support for sanitizing arrays in SQL ORDER clauses. This is useful when using MySQL `ORDER BY FIELD()` to return records in a predetermined way. ```ruby Tag.order(['field(id, ?', [1,3,2]].to_sql # => SELECT "tags".* FROM "tags" ORDER BY field(id, 1,3,2) ``` Prior to this, developers must be careful to sanitize `#order` arguments themselves.
* | | Do not omit parentheses [ci skip]Ryuta Kamizono2015-10-251-1/+1
| | |
* | | Refactor Calculations#execute_grouped_calculation and clean AR test caseRafael Sales2015-10-221-10/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * When tried to use `Company#accounts` test/models/company.rb I got: ``` ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: accounts.company_id: SELECT COUNT(*) AS count_all, "companies"."firm_id" AS companies_firm_id FROM "companies" INNER JOIN "accounts" ON "accounts"."company_id" = "companies"."id" GROUP BY "companies"."firm_id" ``` * The refactor on Calculations class was just to simplify the code
* | | Fix generated projection fields in group by queryRafael Sales2015-10-221-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Closes #21922 Let `Book(id, author_id)`, `Photo(id, book_id, author_id)` and `Author(id)` Running `Book.group(:author_id).joins(:photos).count` will produce: * Rails 4.2 - conflicts `author_id` in both projection and group by: ```sql SELECT COUNT(*) AS count_all, author_id AS author_id FROM "books" INNER JOIN "photos" ON "photos"."book_id" = "books"."id" GROUP BY author_id ``` * Master (9d02a25) - conflicts `author_id` only in projection: ```sql SELECT COUNT(*) AS count_all, author_id AS author_id FROM "books" INNER JOIN "photos" ON "photos"."book_id" = "books"."id" GROUP BY "books"."author_id" ``` * With this fix: ```sql SELECT COUNT(*) AS count_all, "books"."author_id" AS books_author_id FROM "books" INNER JOIN "photos" ON "photos"."book_id" = "books"."id" GROUP BY "books"."author_id" ```
* | | Merge pull request #20653 from repinel/allow-arel-select-countSean Griffin2015-10-201-1/+3
|\ \ \ | | | | | | | | Allow select using Arel and perform a count
| * | | Allow select with Arel and count as well as calculations with ArelRoque Pinel2015-06-301-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | It allows a query like `User.select(:name).count` to be written using Arel as `User.select(User.arel_table[:name]).count`. It exposes the calculations API to accept Arel nodes: `User.count(User.arel_table[:name])`, `User.sum(User.arel_table[:id])`, `Account.average(Account.arel_table[:credit_limit])`, `Account.maximum(Account.arel_table[:credit_limit])` and `Account.minimum(Account.arel_table[:credit_limit])`.
* | | | Qualify column names in calculationSoutaro Matsumoto2015-10-201-1/+1
| | | | | | | | | | | | | | | | Column names inserted via `group` have to be qualified with table name.
* | | | Green version of moving the handling of supported arguments to `where`yui-knk2015-10-182-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit follow up of 4d8f62d. The difference from 4d8f62d are below: * Change `WhereClauseFactory` to accept `Arel::Nodes::Node` * Change test cases of `relation_test.rb`
* | | | Revert "Move the handling of supported arguments to `where`"Rafael Mendonça França2015-10-172-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | This reverts commit 4d8f62dcfa0a5157b3facbd71f75fc6639636347. Reason: This broke the build. Please recommit again when it is green.
* | | | Move the handling of supported arguments to `where`Sean Griffin2015-10-162-3/+1
| | | | | | | | | | | | | | | | | | | | | | | | `WhereClauseFactory` handles all other branches based on argument types, so the code fits more naturally here, and it's just where the responsibility belongs.
* | | | `where` raises ArgumentError on unsupported types.Jake Worth2015-10-161-0/+2
| | | | | | | | | | | | | | | | [#20473]
* | | | applies new doc guidelines to Active Record.Yves Senn2015-10-145-55/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The focus of this change is to make the API more accessible. References to method and classes should be linked to make it easy to navigate around. This patch makes exzessiv use of `rdoc-ref:` to provide more readable docs. This makes it possible to document `ActiveRecord::Base#save` even though the method is within a separate module `ActiveRecord::Persistence`. The goal here is to bring the API closer to the actual code that you would write. This commit only deals with Active Record. The other gems will be updated accordingly but in different commits. The pass through Active Record is not completely finished yet. A follow up commit will change the spots I haven't yet had the time to update. /cc @fxn
* | | | `private def` breaks RDoc. Move meathod to preserve the docs.Yves Senn2015-10-131-6/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The rdoc parser seems to trip on the `private def` construct. Public methods following a method defined with `private def` are not visible inside the module docs but are appended to the top-most module. For example the method `ActiveRecord::QueryMethods#distinct` was listed under `ActiveRecord#distinct`. /cc @sgrif
* | | | docs, :nodoc: `FromClause`, `QueryAttribute` and `WhereClauseFactory`.Yves Senn2015-10-133-3/+3
| | | | | | | | | | | | | | | | [ci skip]
* | | | docs, recognize code examples as Ruby in `Relation::QueryMethods` [ci skip]Yves Senn2015-10-131-33/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Also unify the format of code example output. Only use `# =>` if the actual return value is described. Otherwise simply use `#`. Conflicts: activerecord/lib/active_record/relation/query_methods.rb
* | | | docs, nodoc internal Active Record `DelegateCache`. [ci skip]Yves Senn2015-10-131-3/+3
| | | |
* | | | docs, fix highlighting for code examples in calculations.rb [ci skip]Yves Senn2015-10-131-20/+20
| | | |
* | | | Remove unused requireakihiro172015-10-081-1/+0
| | | | | | | | | | | | | | | | `require 'active_support/core_ext/string/filters'` was added in b3bfa36. However, it is no longer needed from 3ae981814.
* | | | Fix AC::Parameters not being sanitized for query methods.Guo Xiang Tan2015-10-021-5/+3
| | | |
* | | | Merge pull request #21775 from amitsuroliya/fix_column_alias_forRafael Mendonça França2015-09-261-1/+0
|\ \ \ \ | | | | | | | | | | `column_alias_for` method is no more supporting *keys [ci skip]
| * | | | `column_alias_for` method is no more supporting *keys [ci skip]amitkumarsuroliya2015-09-261-1/+0
| | | | |
* | | | | Fix `ActiveRecord::PredicateBuilder` docs. as `register_handler` no more ↵amitkumarsuroliya2015-09-261-1/+1
|/ / / / | | | | | | | | | | | | ClassMethod, Since commit https://github.com/rails/rails/commit/a3936bbe21f4bff8247f890cacfd0fc882921003 [ci skip]
* | | | Correcting `ActiveRecord::ReadOnlyRecord` Error Message [ci skip]amitkumarsuroliya2015-09-261-1/+1
| | | |
* | | | docs, add missing closing bracket. [ci skip]amitkumarsuroliya2015-09-251-1/+1
| | | |
* | | | remove warning from Calculations#sumyuuji.yaginuma2015-09-231-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | This removes the following warning. ``` activerecord/lib/active_record/relation/calculations.rb:74: warning: `&' interpreted as argument prefix ```
* | | | Fix arguments of `AR::Calculations#sum`yui-knk2015-09-231-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Arguments of `#sum` does not match with other shortcuts methods (count, average, minimum, and maximum). This commit fix these two points: * call `super` with only block arguments First argument of `super` method, `Enumerable#sum`, is `identity` and first argument of `AR::Calculations#sum` is `column_name`. `Enumerable#sum` does not expect `column_name` to be passed. * Change first argument of `sum` from array arguemnt to single argument to match other shortcuts methods. When `sum` accept array arguemnt, user can pass multi arguments and an exception is raised from `calculate`.
* | | | Ensure aliased attributes passed to `select` are quoted if using `from`Sean Griffin2015-09-211-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | Fixes #21488 [Sean Griffin & johanlunds]
* | | | Reduce calls to stringify_keys.Guo Xiang Tan2015-09-073-4/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Stackprof output truncated. ``` TOTAL (pct) SAMPLES (pct) FRAME 23 (4.7%) 12 (2.4%) Hash#transform_keys 11 (2.2%) 11 (2.2%) block in Hash#transform_keys 30 (6.1%) 7 (1.4%) Hash#stringify_keys ``` Benchmark Script: ``` begin require 'bundler/inline' rescue LoadError => e $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' raise e end gemfile(true) do source 'https://rubygems.org' gem 'rails', path: '~/rails' # master against ref "f1f0a3f8d99aef8aacfa81ceac3880dcac03ca06" gem 'arel', github: 'rails/arel', branch: 'master' gem 'rack', github: 'rack/rack', branch: 'master' gem 'sass' gem 'sprockets-rails', github: 'rails/sprockets-rails', branch: 'master' gem 'sprockets', github: 'rails/sprockets', branch: 'master' gem 'pg' gem 'benchmark-ips' end require 'active_record' require 'benchmark/ips' ActiveRecord::Base.establish_connection('postgres://postgres@localhost:5432/rubybench') ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name, :email t.timestamps null: false end end class User < ActiveRecord::Base; end attributes = { name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com", } 1000.times { User.create!(attributes) } Benchmark.ips(5, 3) do |x| x.report('where with hash') { User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") } x.report('where with string') { User.where("users.name = ?", "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") } x.compare! end key = if RUBY_VERSION < '2.2' :total_allocated_object else :total_allocated_objects end before = GC.stat[key] User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") after = GC.stat[key] puts "Total Allocated Object: #{after - before}" ``` Before: ``` Calculating ------------------------------------- where with hash 2.796k i/100ms where with string 4.338k i/100ms ------------------------------------------------- where with hash 29.177k (± 1.5%) i/s - 148.188k where with string 47.419k (± 2.8%) i/s - 238.590k Comparison: where with string: 47419.0 i/s where with hash: 29176.6 i/s - 1.63x slower Total Allocated Object: 85 ``` After: ``` Calculating ------------------------------------- where with hash 2.895k i/100ms where with string 4.416k i/100ms ------------------------------------------------- where with hash 30.758k (± 2.0%) i/s - 156.330k where with string 47.708k (± 2.6%) i/s - 238.464k Comparison: where with string: 47707.9 i/s where with hash: 30757.7 i/s - 1.55x slower Total Allocated Object: 84 ```
* | | | #where fails if opts.responds_to?(:==) unexpectedlySamuel Williams2015-09-051-1/+1
| | | | | | | | | | | | Sometimes opts passed in might respond to ==, e.g. `Arel::Nodes::Grouping`. In this case, `opts == :chain` returns `Arel::Nodes::Equality` which causes odd behaviour. Prefer `if :chain == opts` which guarantees that `Symbol#==` would be invoked. Alternatively consider `eql?`.
* | | | Don't allocate a bunch of strings in `Relation::Merger`Sean Griffin2015-09-021-4/+8
| | | | | | | | | | | | | | | | | | | | | | | | Since the strings are dynamically computed from a constant, the actual strings we're creating are a known set. We can compute them ahead of time, and reduce the number of allocations in that method.
* | | | Add ActiveRecord::Relation#in_batchesSina Siadat2015-08-072-9/+156
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `in_batches` yields Relation objects if a block is given, otherwise it returns an instance of `BatchEnumerator`. The existing `find_each` and `find_in_batches` methods work with batches of records. The new API allows working with relation batches as well. Examples: Person.in_batches.each_record(&:party_all_night!) Person.in_batches.update_all(awesome: true) Person.in_batches.delete_all Person.in_batches.map do |relation| relation.delete_all sleep 10 # Throttles the delete queries end
* | | | Extra caller details added to ActiveRecord::RecordNotFoundSameer Rahmani2015-07-211-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ActiveRecord::RecordNotFound modified to store model name, primary_key and id of the caller model. It allows the catcher of this exception to make a better decision to what to do with it. For example consider this simple example: class SomeAbstractController < ActionController::Base rescue_from ActiveRecord::RecordNotFound, with: :redirect_to_404 private def redirect_to_404(e) return redirect_to(posts_url) if e.model == 'Post' raise end end
* | | | Freeze string literals when not mutated.schneems2015-07-192-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution? To look at memory: ```ruby require 'get_process_mem' mem = GetProcessMem.new GC.start GC.disable 1_114.times { " " } before = mem.mb after = mem.mb GC.enable puts "Diff: #{after - before} mb" ``` Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests. To look at raw speed: ```ruby require 'benchmark/ips' number_of_objects_reduced = 1_114 Benchmark.ips do |x| x.report("freeze") { number_of_objects_reduced.times { " ".freeze } } x.report("no-freeze") { number_of_objects_reduced.times { " " } } end ``` We get the results ``` Calculating ------------------------------------- freeze 1.428k i/100ms no-freeze 609.000 i/100ms ------------------------------------------------- freeze 14.363k (± 8.5%) i/s - 71.400k no-freeze 6.084k (± 8.1%) i/s - 30.450k ``` Now we can do some maths: ```ruby ips = 6_226k # iterations / 1 second call_time_before = 1.0 / ips # seconds per iteration ips = 15_254 # iterations / 1 second call_time_after = 1.0 / ips # seconds per iteration diff = call_time_before - call_time_after number_of_objects_reduced * diff * 100 # => 0.4530373333993266 miliseconds saved per request ``` So we're shaving off 1 second of execution time for every 220 requests. Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep. p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37) please [give me a pull request to the appropriate file](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37), or open an issue in LetItGo so we can track and freeze more strings. Keep those strings Frozen ![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
* | | | Fix regression caused by a01d164bRafael Mendonça França2015-07-071-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When preload is used in a default scope the preload_values were returning nested arrays and causing the preloader to fail because it doesn't know how to deal with nested arrays. So before calling preload! we need to splat the arguments. This is not needed to includes because it flatten its arguments.
* | | | [skip ci] #distinct instead of #uniqJon Atack2015-07-031-2/+3
|/ / / | | | | | | | | | | | | | | | | | | | | | as #uniq will be removed from Rails 5.0 as per the Active Support exception raised: ActiveSupport::DeprecationException: DEPRECATION WARNING: uniq is deprecated and will be removed from Rails 5.0 (use distinct instead).
* | | Update .pluck documentation on uniqPrem Sichanugrist2015-06-261-1/+1
| | | | | | | | | | | | | | | | | | This is to show users that they can chain `.uniq` and `.pluck` to get the `DISTINCT column` result. They don't have to do `DISTINCT column` themselves.
* | | Include `Enumerable` in `ActiveRecord::Relation`Sean Griffin2015-06-193-17/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | After discussing, we've decided it makes more sense to include it. We're already forwarding every conflicting method to `to_a`, and there's no conflation of concerns. `Enumerable` has no mutating methods, and it just allows us to simplify the code. No existing methods will have a change in behavior. Un-overridden Enumerable methods will simply delegate to `each`. [Sean Griffin & bogdan]
* | | Use `Enumerable#sum` on `ActiveRecord::Relation` when a block is givenSean Griffin2015-06-191-2/+6
| | | | | | | | | | | | | | | | | | | | | | | | This matches our behavior in other cases where useful enumerable methods might have a different definition in `Relation`. Wanting to actually enumerate over the records in this case is completely reasonable, and wanting `.sum` is reasonable for the same reason it is on `Enumerable` in the first place.
* | | Merge pull request #20362 from kddeisz/enumerable_pluckRafael Mendonça França2015-06-011-0/+4
|\ \ \ | | | | | | | | Allow Enumerable#pluck to take a splat.
| * | | Allow Enumerable#pluck to take a splat.Kevin Deisz2015-05-291-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | This allows easier integration with ActiveRecord, such that AR#pluck will now use Enumerable#pluck if the relation is loaded, without needing to hit the database.
* | | | Ensure symbols passed to `select` are always quotedSean Griffin2015-05-301-9/+7
|/ / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Our general contract in Active Record is that strings are assumed to be SQL literals, and symbols are assumed to reference a column. If a from clause is given, we shouldn't include the table name, but we should still quote the value as if it were a column. Upon fixing this, the tests were still failing on SQLite. This was because the column name being returned by the query was `"\"join\""` instead of `"join"`. This is actually a bug in SQLite that was fixed a long time ago, but I was using the version of SQLite included by OS X which has this bug. Since I'm guessing this will be a common case for contributors, I also added an explicit check with a more helpful error message. Fixes #20360
* | | Fix the shadowing warning for `reflection`Roque Pinel2015-05-281-2/+2
| | |
* | | Merge pull request #20196 from huoxito/preload-association-and-mergesRafael Mendonça França2015-05-281-1/+23
|\ \ \ | | | | | | | | Properly append preload / includes args on Merger
| * | | Properly append preload / includes args on MergerWashington Luiz2015-05-281-1/+23
| | |/ | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Couldn't find other way to get the association name from a given class other than looping through `reflect_on_all_associations` reflections .. Noticed this one while looking at this example: ```ruby class Product < ActiveRecord::Base has_many :variants has_many :translations end class Translation < ActiveRecord::Base belongs_to :product end class Variant < ActiveRecord::Base belongs_to :product end class BugTest < Minitest::Test def test_merge_stuff product = Product.create! name: 'huhu' variant = Variant.create! product_id: product.id Translation.create! locale: 'en', product_id: product.id product_relation = Product.all .preload(:translations) .joins(:translations) .merge(Translation.where(locale: 'en')) .where(name: 'huhu') assert_equal variant, Variant.joins(:product).merge(product_relation).first end end ```