Reputation: 973
I am using public_activity gem in my app and to track the owner who created the record to track the event model, I am using devise and I have two types of users, individual and company , my code is this to track the owner
class Event < ActiveRecord::Base
include PublicActivity::Model
tracked owner: ->(controller, model) { controller && controller.current_individual }
end
Here the problem is I want to track the owner as current_company if the company is signed in , but public_activity gem doesnt provide multiple owner types
I want to track that if the current_individual is signed in then the owner type and id would be of individual and if company is signed in then according to that.
what i am doing is
class Event < ActiveRecord::Base
include PublicActivity::Model
tracked owner: ->(controller, model) { controller && controller.individual_signed_in? ? controller.current_individual : controller.current_company }
end
but i am getting owner id and type when individual is logged in but not getting owner type and id when company is logged in
Upvotes: 1
Views: 1055
Reputation: 3235
I hope my approach does not make people's eyes bleed. It might not be the best code to copy (happy for tips) but I hope the idea is helpful (and it does work) :-p
I have a large network of model elements that can be used to create a "preplan" for anything from a single building to an entire university campus full of dozens of structures, hundreds of fire hydrants... And a structure can have all kinds of things (roof, accesses (doors), hazardous materials, fire detection systems, protection systems, sprinklers, and so on).
Any element can have one or more photos attached/edited/deleted.
Polymorphic owner: I like to adorn the activity tracking to show who added/edited/deleted a photo and for what "owning" element, regardless of the class.
So a reusable partial is used to put up a nice "Add Photos" drag-n-dop landing zone for any element. The partial is passed a local to tell what the "owning" element is (the structure, or a roof, or an alarm system):
= render partial: 'photos/photos', locals: {owner: item}
And inside that partial, the owning element is parsed a bit further... (probably unnecessary, could just pass the owner along and parse it out in the controller, now that I look at it!)
= link_to new_photo_path(:owner_id => owner, :owner_class => owner.class, :tag => owner.class::TAG),
Then the controller has some actions to deal with the "owning" object...
class PhotosController < ApplicationController
before_action :set_owning_object, only: [:new, :index]
before_action :get_owning_object, only: [:create, :update]
...
def set_owning_object
@owner_class = params["owner_class"]
@owner_id = params["owner_id"]
@photo_tag = params["tag"]
session[:owner_class] = @owner_class if @owner_class
session[:owner_id] = @owner_id if @owner_id
session[:photo_tag] = @photo_tag if @photo_tag
# Unsafe reflection method constantize called with parameter value
# Let's whitelist the allowable classes that can have Photos
if @owner_class
if (%w(Preplan Structure Organization PreplanLayout StagingArea) + Structure::Default_Elements).include? @owner_class
@owning_object = (@owner_class.constantize).find(@owner_id)
else
Rails.logger.warn("OWNING CLASS NEEDS TO BE ADDED: #{@owner_class} was not cleared for use in #{__method__}.")
end
else
@owning_object = nil
end
end
And the controller manually adds activities under the desired CRUD actions with this highly polymorphic "owner" class (which includes HasActivities module that includes the public_activity gem):
def create
authorize Photo
@photo = Photo.new(photo_params)
@photo.tags << @photo_tag
add_photo(@owning_object, @photo)
respond_to do |format|
if @photo.save
if @owning_object.respond_to? :create_activity
@owning_object.create_activity(:add_photo,
owner: view_context.current_user,
organization: view_context.current_org,
recipient: @owning_object,
parameters: { name: @photo.caption, file: @photo.photo_name, owner: @owning_object.name })
end
pseudo_url = owning_object_url(@owning_object)
format.html {
redirect_to pseudo_url, notice: "Photo was successfully added."
}
format.json {render json: { photo: render_to_string(partial: 'photos/photo', layout: false, :formats => [:html], locals: { photo: @photo, photo_counter: @photo.id }) }}
else
format.html {render action: 'new'}
format.json {render json: { error: @photo.errors.full_messages.join(',') }, :status => 406}
end
end
end
def update
authorize @photo
if @photo.update_attributes(photo_params)
@photo.create_activity(:update,
owner: view_context.current_user,
organization: view_context.current_org,
recipient: @owning_object,
parameters: { name: @photo.caption, file: @photo.photo_name })
respond_to do |format|
format.js
end
end
end
def destroy
authorize @photo
@photo.create_activity(key: 'photo.destroy',
owner: current_user,
organization: view_context.current_org,
parameters: { name: @photo.caption, file: @photo.photo_name })
@photo.destroy
respond_to do |format|
format.html {redirect_to :back}
format.json {head :no_content}
end
end
The aforementioned HasActivities module:
module HasActivities
extend ActiveSupport::Concern
included do
include PublicActivity::Common
end
end
Upvotes: 1
Reputation: 7655
Actually owner
is polymorphic as can be seen here:
create_table :activities do |t|
t.belongs_to :trackable, :polymorphic => true
t.belongs_to :owner, :polymorphic => true
t.string :key
t.text :parameters
t.belongs_to :recipient, :polymorphic => true
t.timestamps
end
So it's not a problem to assign owner of different type.
If you want to assign company as owner when company's user is signed-in and a person, when personal account is signed in, you should just make appropriate changes in your code:
tracked owner: ->(controller, model) { controller.current_user.organization? ? controller.current_user.organization : controller.current_user.person }
Upvotes: 1