Skip to content

Commit

Permalink
Global configuration for :ignore_log_data option
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitryTsepelev committed Mar 15, 2019
1 parent ffa0f79 commit 04320b3
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 92 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

## master

- PR [#111](https://github.com/palkan/logidze/pull/111) Global configuration for `:ignore_log_data` option ([@dmitrytsepelev][])

Now it's possible to avoid loading `log_data` from the DB by default with

```ruby
Logidze.ignore_log_data_by_default = true
```

In cases when `ignore_log_data: false` is explicitly passed to the `ignore_log_data` the default setting is being overriden. Also, it's possible to change it inside the block:

```ruby
Logidze.with_log_data do
Post.find(params[:id]).log_data
end
```

- PR [#110](https://github.com/palkan/logidze/pull/110) Add `reset_log_data` API to nullify log_data column ([@Arkweid][])

Usage:
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,21 @@ class User < ActiveRecord::Base
end
```

After that, each time you use `User.all` (or any other relation method) `log_data` won't be loaded from the DB.
If you want Logidze to always behave this way - you can set up a global configuration option:

```ruby
Rails.application.config.logidze.ignore_log_data_by_default = true
```

However, you can override it by explicitly passing `ignore_log_data: false` to the `ignore_log_data`. Also, it's possible to change it temporary inside the block:

```ruby
Logidze.with_log_data do
Post.find(params[:id]).log_data
end
```

When `ignore_log_data` is turned on, each time you use `User.all` (or any other relation method) `log_data` won't be loaded from the DB.

The chart below shows the difference in PG query time before and after turning `ignore_log_data` on. (Special thanks to [@aderyabin](https://github.com/aderyabin) for sharing it.)

Expand Down
47 changes: 36 additions & 11 deletions lib/logidze.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,48 @@ module Logidze
class << self
# Determines if Logidze should append a version to the log after updating an old version.
attr_accessor :append_on_undo

attr_writer :associations_versioning

def associations_versioning
@associations_versioning || false
end
end

# Temporary disable DB triggers.
#
# @example
# Logidze.without_logging { Post.update_all(active: true) }
def self.without_logging
ActiveRecord::Base.transaction do
ActiveRecord::Base.connection.execute "SET LOCAL logidze.disabled TO on;"
res = yield
ActiveRecord::Base.connection.execute "SET LOCAL logidze.disabled TO DEFAULT;"
res
# Determines if Logidze should exclude log data from SELECT statements
attr_writer :ignore_log_data_by_default

def ignore_log_data_by_default
@ignore_log_data_by_default || false
end

attr_writer :force_load_log_data

def force_load_log_data
@force_load_log_data || false
end

# Temporary disable DB triggers.
#
# @example
# Logidze.without_logging { Post.update_all(active: true) }
def without_logging
ActiveRecord::Base.transaction do
ActiveRecord::Base.connection.execute "SET LOCAL logidze.disabled TO on;"
res = yield
ActiveRecord::Base.connection.execute "SET LOCAL logidze.disabled TO DEFAULT;"
res
end
end

# Temporary turn off ignore_log_data_by_default config
#
# @example
# Logidze.with_log_data { Post.update_all(active: true) }
def with_log_data
Logidze.force_load_log_data = true
yield
ensure
Logidze.force_load_log_data = false
end
end
end
14 changes: 12 additions & 2 deletions lib/logidze/has_logidze.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@ module ClassMethods # :nodoc:
# Include methods to work with history.
#
# rubocop:disable Naming/PredicateName
def has_logidze(ignore_log_data: false)
def has_logidze(ignore_log_data: nil)
include Logidze::Model
include Logidze::IgnoreLogData if ignore_log_data
include Logidze::IgnoreLogData

@ignore_log_data = ignore_log_data
end

def ignores_log_data?
if @ignore_log_data.nil? && Logidze.ignore_log_data_by_default
!Logidze.force_load_log_data
else
@ignore_log_data
end
end
end
end
Expand Down
14 changes: 9 additions & 5 deletions lib/logidze/ignore_log_data.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# frozen_string_literal: true

module Logidze
# Add `has_logidze` method to AR::Base
module IgnoreLogData
module IgnoreLogData # :nodoc:
extend ActiveSupport::Concern

included do
Expand All @@ -16,14 +15,19 @@ module IgnoreLogData

require "logidze/ignore_log_data/missing_attribute_patch"
include MissingAttributePatch

require "logidze/ignore_log_data/default_scope_patch"
include DefaultScopePatch
end

self.ignored_columns += ["log_data"]

scope :with_log_data, -> { select(column_names + ["log_data"]) }
end

module ClassMethods # :nodoc:
def with_log_data
select(column_names + ["log_data"])
class_methods do
def self.default_scope
ignores_log_data? ? super : super.with_log_data
end
end
end
Expand Down
25 changes: 25 additions & 0 deletions lib/logidze/ignore_log_data/default_scope_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Logidze
module IgnoreLogData
# Since Rails caches ignored_columns, we have to patch .column_names and
# .unscoped methods to make conditional log_data loading possible
module DefaultScopePatch
extend ActiveSupport::Concern

class_methods do
def column_names
ignores_log_data? ? super : super + ["log_data"]
end

def unscoped
if ignores_log_data?
super
else
block_given? ? with_log_data.scoping { yield } : with_log_data
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/logidze/ignore_log_data/ignored_columns.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module Relation # :nodoc:
private

def build_select(arel)
if select_values.blank? && klass.ignored_columns.any?
if select_values.blank? && klass.ignored_columns.any? && ignores_log_data?
arel.project(*arel_columns(klass.column_names - klass.ignored_columns))
else
super
Expand Down
4 changes: 3 additions & 1 deletion lib/logidze/ignore_log_data/missing_attribute_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ module IgnoreLogData
# from Rails 4 - raise ActiveModel::MissingAttributeError
module MissingAttributePatch
def log_data
raise ActiveModel::MissingAttributeError if attributes["log_data"].nil?
if self.class.ignores_log_data? && attributes["log_data"].nil?
raise ActiveModel::MissingAttributeError
end

super
end
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/app/models/always_logged_post.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AlwaysLoggedPost < ActiveRecord::Base
has_logidze ignore_log_data: false

self.table_name = "posts"
end
2 changes: 1 addition & 1 deletion spec/dummy/app/models/comment.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Comment < ActiveRecord::Base
has_logidze
has_logidze ignore_log_data: false
belongs_to :article
end
6 changes: 5 additions & 1 deletion spec/dummy/app/models/not_logged_post.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
class NotLoggedPost < Post
class NotLoggedPost < ActiveRecord::Base
has_logidze ignore_log_data: true

self.table_name = "posts"

belongs_to :user
end
52 changes: 25 additions & 27 deletions spec/dummy/db/schema.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
Expand All @@ -10,49 +11,46 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2017_02_20_153105) do
ActiveRecord::Schema.define(version: 20170220153105) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "articles", id: :serial, force: :cascade do |t|
t.string "title"
t.integer "rating"
t.boolean "active"
t.integer "user_id"
t.jsonb "log_data"
create_table "articles", force: :cascade do |t|
t.string "title"
t.integer "rating"
t.boolean "active"
t.integer "user_id"
t.jsonb "log_data"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_articles_on_user_id"
end

create_table "comments", id: :serial, force: :cascade do |t|
t.text "content"
t.jsonb "log_data"
t.integer "article_id"
create_table "comments", force: :cascade do |t|
t.text "content"
t.jsonb "log_data"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["article_id"], name: "index_comments_on_article_id"
end

create_table "posts", id: :serial, force: :cascade do |t|
t.string "title"
t.integer "rating"
t.boolean "active"
t.jsonb "meta"
t.integer "user_id"
create_table "posts", force: :cascade do |t|
t.string "title"
t.integer "rating"
t.boolean "active"
t.jsonb "meta"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_posts_on_user_id"
end

create_table "users", id: :serial, force: :cascade do |t|
t.string "name"
t.integer "age"
t.boolean "active"
t.jsonb "extra"
t.string "settings", array: true
t.jsonb "log_data"
create_table "users", force: :cascade do |t|
t.string "name"
t.integer "age"
t.boolean "active"
t.jsonb "extra"
t.string "settings", array: true
t.jsonb "log_data"
t.datetime "time"
end

Expand Down
Loading

0 comments on commit 04320b3

Please sign in to comment.