Skip to content

Instantly share code, notes, and snippets.

@dgertych-monterail
Created October 3, 2014 07:57
Show Gist options
  • Select an option

  • Save dgertych-monterail/981ca8ccf2269bba6548 to your computer and use it in GitHub Desktop.

Select an option

Save dgertych-monterail/981ca8ccf2269bba6548 to your computer and use it in GitHub Desktop.
Tags cache issue solved with https://github.com/jenseng/hair_trigger
diff --git a/README.md b/README.md
index e4e7348..3aa3845 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,10 @@ Okta trial information you can find [here](https://monterail.hackpad.com/Cooleaf
If there are two ENV variables set: `BASIC_USERNAME` and `BASIC_PASSWORD`
whole application will be guarded by basic auth.
+### Tags Cache
+Tags cache attribute for Role and Persona is updated by database stored procedure on taggings table.
+Checkout details in `app/models/taggins.rb`
+
### Testing
We are using [poltergeist](https://github.com/jonleighton/poltergeist/tree/v1.5.0) - see [installation instructions](https://github.com/jonleighton/poltergeist/tree/v1.5.0#installation)
diff --git a/app/controllers/api/v1/hr/structures.rb b/app/controllers/api/v1/hr/structures.rb
index f46c98f..00f3bd4 100644
--- a/app/controllers/api/v1/hr/structures.rb
+++ b/app/controllers/api/v1/hr/structures.rb
@@ -59,7 +59,7 @@ module API::V1::HR
Tag.transaction do
role = roles[user[:id].to_i]
tag = tags[user[:tag].to_i]
- add_tag_to_role(role, tag)
+ role.tags << tag
end
end
end
@@ -98,11 +98,6 @@ module API::V1::HR
end
end
- def add_tag_to_role(role, tag)
- role.tags << tag
- role.refresh_tags_cache
- end
-
def map_users_hash_with(key)
permitted_params[:users].try(:map) { |user| user[key].to_i }
end
diff --git a/app/controllers/api/v1/hr/users.rb b/app/controllers/api/v1/hr/users.rb
index 7af32f2..7489e2d 100644
--- a/app/controllers/api/v1/hr/users.rb
+++ b/app/controllers/api/v1/hr/users.rb
@@ -115,7 +115,6 @@ module API::V1::HR
Tag.transaction do
update_structure_tags(role, permitted_params[:structures])
update_hidden_tags(role, permitted_params[:hidden].uniq)
- role.refresh_tags_cache
end
represent role.user, current_organization, with: ::HR::UserRepresenter
diff --git a/app/controllers/api/v1/main/users.rb b/app/controllers/api/v1/main/users.rb
index b3d29ae..7bf6179 100644
--- a/app/controllers/api/v1/main/users.rb
+++ b/app/controllers/api/v1/main/users.rb
@@ -98,7 +98,6 @@ module API::V1::Main
if role_params = user_params.delete(:role)
Tag.transaction do
update_structure_tags(role, role_params[:structures])
- role.refresh_tags_cache
end
end
@@ -109,7 +108,6 @@ module API::V1::Main
role.tags.delete(role.tags.interest)
role.tags << current_organization.tags.interest.where(id: interests.uniq).
where(active: true)
- role.refresh_tags_cache
end
end
diff --git a/app/models/persona.rb b/app/models/persona.rb
index 9b14528..5833bd8 100644
--- a/app/models/persona.rb
+++ b/app/models/persona.rb
@@ -2,10 +2,4 @@ class Persona < ActiveRecord::Base
belongs_to :personable, polymorphic: true
has_many :taggings, as: :taggable, dependent: :destroy
has_many :tags, through: :taggings
-
- after_create :refresh_tags_cache
-
- def refresh_tags_cache
- self.update_attributes!(tags_cache: tag_ids)
- end
end
diff --git a/app/models/role.rb b/app/models/role.rb
index b5ed1eb..51c770f 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -17,10 +17,6 @@ class Role < ActiveRecord::Base
scope :active, ->{ where(active: true) }
- def refresh_tags_cache
- self.update_attributes!(tags_cache: tag_ids)
- end
-
def self.for(organization)
find_by(organization: organization)
end
diff --git a/app/models/tagging.rb b/app/models/tagging.rb
index 5c66273..e4a8a8f 100644
--- a/app/models/tagging.rb
+++ b/app/models/tagging.rb
@@ -8,4 +8,25 @@ class Tagging < ActiveRecord::Base
def interest?
tag.try(:type) == "interest"
end
+
+ trigger.after(:insert, :delete).
+ declare('row RECORD; tbl_name TEXT; tags_cache_sql TEXT;') do
+ <<-SQL
+ IF TG_OP = 'INSERT' THEN
+ row := NEW;
+ ELSIF TG_OP = 'DELETE' THEN
+ row := OLD;
+ END IF;
+ IF row.taggable_type IN ('Persona', 'Role') THEN
+ tbl_name := LOWER(row.taggable_type) || 's';
+ tags_cache_sql = 'SELECT tag_id FROM taggings'
+ || ' WHERE taggable_type = ' || quote_literal(row.taggable_type)
+ || ' AND taggable_id = ' || quote_literal(row.taggable_id);
+
+ EXECUTE 'UPDATE ' || quote_ident(tbl_name)
+ || ' SET tags_cache = ARRAY(' || tags_cache_sql || ')'
+ || ' WHERE id = ' || quote_literal(row.taggable_id);
+ END IF;
+ SQL
+ end
end
diff --git a/app/services/registration_form.rb b/app/services/registration_form.rb
index d856bcb..2597321 100644
--- a/app/services/registration_form.rb
+++ b/app/services/registration_form.rb
@@ -158,7 +158,6 @@ class RegistrationForm
def persist!
user.save!
- role.refresh_tags_cache
registration.destroy
end
diff --git a/db/migrate/20141001110815_create_trigger_taggings_insert_delete.rb b/db/migrate/20141001110815_create_trigger_taggings_insert_delete.rb
new file mode 100644
index 0000000..691997a
--- /dev/null
+++ b/db/migrate/20141001110815_create_trigger_taggings_insert_delete.rb
@@ -0,0 +1,34 @@
+# This migration was auto-generated via `rake db:generate_trigger_migration'.
+# While you can edit this file, any changes you make to the definitions here
+# will be undone by the next auto-generated trigger migration.
+
+class CreateTriggerTaggingsInsertDelete < ActiveRecord::Migration
+ def up
+ create_trigger("taggings_after_insert_delete_row_tr", :generated => true, :compatibility => 1).
+ on("taggings").
+ after(:insert, :delete).
+ declare('row RECORD; tbl_name TEXT; tags_cache_sql TEXT;') do
+ <<-SQL_ACTIONS
+ IF TG_OP = 'INSERT' THEN
+ row := NEW;
+ ELSIF TG_OP = 'DELETE' THEN
+ row := OLD;
+ END IF;
+ IF row.taggable_type IN ('Persona', 'Role') THEN
+ tbl_name := LOWER(row.taggable_type) || 's';
+ tags_cache_sql = 'SELECT tag_id FROM taggings'
+ || ' WHERE taggable_type = ' || quote_literal(row.taggable_type)
+ || ' AND taggable_id = ' || quote_literal(row.taggable_id);
+
+ EXECUTE 'UPDATE ' || quote_ident(tbl_name)
+ || ' SET tags_cache = ARRAY(' || tags_cache_sql || ')'
+ || ' WHERE id = ' || quote_literal(row.taggable_id);
+ END IF;
+ SQL_ACTIONS
+ end
+ end
+
+ def down
+ drop_trigger("taggings_after_insert_delete_row_tr", "taggings", :generated => true)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 7a19608..8a24f4b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140929154205) do
+ActiveRecord::Schema.define(version: 20141001110815) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -496,4 +496,27 @@ ActiveRecord::Schema.define(version: 20140929154205) do
t.datetime "updated_at"
end
+ create_trigger("taggings_after_insert_delete_row_tr", :generated => true, :compatibility => 1).
+ on("taggings").
+ after(:insert, :delete).
+ declare('row RECORD; tbl_name TEXT; tags_cache_sql TEXT;') do
+ <<-SQL_ACTIONS
+ IF TG_OP = 'INSERT' THEN
+ row := NEW;
+ ELSIF TG_OP = 'DELETE' THEN
+ row := OLD;
+ END IF;
+ IF row.taggable_type IN ('Persona', 'Role') THEN
+ tbl_name := LOWER(row.taggable_type) || 's';
+ tags_cache_sql = 'SELECT tag_id FROM taggings'
+ || ' WHERE taggable_type = ' || quote_literal(row.taggable_type)
+ || ' AND taggable_id = ' || quote_literal(row.taggable_id);
+
+ EXECUTE 'UPDATE ' || quote_ident(tbl_name)
+ || ' SET tags_cache = ARRAY(' || tags_cache_sql || ')'
+ || ' WHERE id = ' || quote_literal(row.taggable_id);
+ END IF;
+ SQL_ACTIONS
+ end
+
end
diff --git a/spec/factories/personas.rb b/spec/factories/personas.rb
index e703f0a..250ab95 100644
--- a/spec/factories/personas.rb
+++ b/spec/factories/personas.rb
@@ -11,7 +11,6 @@ FactoryGirl.define do
create_list(:interest_tag, 3,
organization: evaluator.personable.organization,
personas: [persona])
- persona.refresh_tags_cache
end
end
diff --git a/spec/requests/api/v1/hr/structures_spec.rb b/spec/requests/api/v1/hr/structures_spec.rb
index a0277a0..aafec0b 100644
--- a/spec/requests/api/v1/hr/structures_spec.rb
+++ b/spec/requests/api/v1/hr/structures_spec.rb
@@ -11,11 +11,6 @@ describe API::V1::HR::Structures do
"/v1/hr/structures/#{structure.id}/#{action}"
end
- def add_tag_to_role(role, tag)
- role.tags << tag
- role.refresh_tags_cache
- end
-
before do
Grape::Endpoint.before_each do |endpoint|
allow(endpoint).to receive(:authenticate!).and_return(true)
@@ -32,8 +27,7 @@ describe API::V1::HR::Structures do
let(:role) { user_with_tag.roles.for(organization) }
before do
- add_tag_to_role(role, tag)
-
+ role.tags << tag
get api_path_to("users_without_tags"), organization: organization.subdomain
end
@@ -60,7 +54,7 @@ describe API::V1::HR::Structures do
describe "with no required tags missing in the database" do
let(:role) { hr.roles.for(organization) }
- before { add_tag_to_role(role, tag) }
+ before { role.tags << tag }
it "should pass" do
put api_path_to("required"), basic_params
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment