Active Record Observer not firing in console/seed - ruby-on-rails-3

I have observers set up to award badges on model changes.
It works when I'm using the view, but I doesn't seem to fire when I do something like :
Photo.create(:user_id => user.id, :file => file) from the console or from the seed file.
Any idea ?
class ExplorerObserver < ActiveRecord::Observer
observe :photo
def after_save(photo)
user = photo.user
Explorer.award_achievements_for(user) unless photo.new_record?
end
end

My mistake, it was a silly issue, but for the archive, here is my answer :
If you have multiple observers, dont put multiple lines like that
config.active_record.observers = :popular_observer
config.active_record.observers = :explorer_observer
instead chain your observers, my previous code was overwriting the observers with the last one !
config.active_record.observers = :popular_observer, :explorer_observer

Did you forget to put it in config/application.rb, inside your Application class?
config.active_record.observers = :photo_observer

Related

Override default scope in active_admin form.has_many

Given a model Post that has_many attachments, and an attachment has a hidden flag. Throughout the app I want to easily say post.attachments and only get the visible ones, so i setup a default scope in the Attachment model (using squeel):
default_scope -> { where { (hidden != true) | (hidden == nil) } }
But the admin page needs to be able to see all attachments for a post, not just the visible ones (so you can toggle the hidden checkbox). The default way of doing this (in admin/posts.rb) uses the default_scope and only lets me edit the visible ones:
f.has_many :attachments do |a|
...
end
I know I could just not use default_scope and instead name it :visible, and then everywhere (except the admin page) say post.attachments.visible but I prefer not having the do that.
How can I unscope the children attachments on the admin page?
Here's the solution I worked out:
In app/admin/posts.rb
f.has_many :attachments, for: [:attachments, f.object.attachments_including_hidden] do |a|
...
end
And in app/models/posts.rb
def attachments_including_hidden
Attachment.unscoped.where( attachable_id: id )
end
(where Attachment model belongs_to: :attachable, polymorphic: true )
What's going on? ActiveAdmin uses Formtastic, which uses Rails Form Builder.
The form.has_many method is an ActiveAdmin method, which calls Formtastic's form.inputs, which in turn calls Rails' fields_for. The :for option will get passed all the way down the fields_for, which can take a collection (as its 2nd arg) so I deliver this collection to it explicitly.

Rails add partial to Simpleform custom inputs

I'm creating a custom SimpleForm input. It utilizes a javascript modal popup to select values.
I can basically get it to work if I include the modal partial in the form view, but I would ideally like to have the custom input push the partial to the template.
However, I can't get it to work. I'm trying this, but it doesn't render the partial correctly.
class ProductCategoryImageSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input
html = ''
html << 'Launch demo modal'
File.open("#{Rails.root}/app/views/product_categories/_browse_modal.html.erb", 'r') do |f|
html << f.read
end
end
end
Any thoughts?
EDIT
I'm apparently too new of a user to post screenshots, but here are links to the differences in functionality:
When I embed the modal code in the form, I get this, which is the desired functionality:
working
When I try to put the modal code in the custom input, I get this instead:
not working
You can also render partial from a custom input using the SimpleForm::FormBuilder instance which is assigned to an instance variable named #builder:
class ProductCategoryImageSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input
#builder.template.render(partial: 'product_categories/browse_modal', locals: { foo: 'bar'})
end
end
Weirdly, it seems I've already answered it here.
Does this work for you?
ERB.new(f.read).result(binding)
PS: Updated with ERB instead of HAML.

Rails 3 Active Admin add preset value to new record

I have tried to do it from the controller and from the active admin override controller and I can't make it work.
A user creates a website.
current_user has an id attribute
website has an user_id attribute
So when I create a new website I want to add the current_user.id into website.user_id. I can't.
Anybody know how?
Right now I need it on the new/create actions but I'll probably need this on the edit/update actions too.
This seems to work for me:
ActiveAdmin.register Website do
controller do
# Do some custom stuff on GET /admin/websites/*/edit
def edit
super do |format|
# Do what you want here ...
#website.user = current_user
end
end
end
end
You should be able to override other controller actions in the same way.
ActiveAdmin.register Model do
# also look in to before_create if hidden on form
before_build do |record|
record.user = current_user
end
end
See https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_dsl.rb#L156
You need to add a 'new' method to the controller. The 'new' method creates an empty website object that will be passed to the form. The default 'new' method just creates an empty #website object. Your 'new' method should create the empty object, and then initialize the value of user to current user:
ActiveAdmin.register Website do
controller do
# Custom new method
def new
#website = Website.new
#website.user = current_user
#set any other values you might want to initialize
end
end

How to show a sidebar conditionally, based on the routing used?

I have a sidebar that will rotate its content based on where the user is (amongst others; in reality also on who the user is, how far her profile is finished and so on).
What I want is a helper that checks against the controller, action and id of the current page.
if the controller is JobsController and the action is show or index, use partial _sidebar_add_your_job.
if the controller is UsersController and the action is show or index, use partial _sidebar_add_your_cv.
The simplified version of my helper, in app/helpers/sidebar_helper.rb is:
module SidebarHelper
def sidebar_partial
if partial
return "sidebar_#{partial}"
end
end
# Determines what sidebar partial to render.
def partial
partial = nil
if ((section == :jobseekers) && current_user.nil?)
partial = :add_cv
elsif ((section == :employers) && current_user.nil?)
partial = :add_job
end
partial
end
def section url = nil
url = request.fullpath if url.nil?
section = nil
if (url == root_path || url.match(/^\/jobs/) )
section = :jobseekers
elsif (url.match(/^\/employer/) || url.match(/\/users\/[a-z0-9]+/) )
section = :employers
end
section
end
end
Especially the last part, where I match regular expresssions against urls is ugly and fails for quite a few cases. Most notably: users/sign_in, users/sign_up` and such. I am relucatant to start maintaining an entire blacklist of these exceptions, it feels too ugly and too tightly coupled to the routes.
How can I best achieve some conditional partial inclusion based on the URL, or controller&action and -in future- on a few more simple conditions such as the role and status of the current user?
How can I test against Controller and its action of the current page/request in a helper?
Please check this post there you can find an easy way to make current controller and action available in your views

rails 3 custom mime type - default view format

I need to render some views without layout.
To skip line :render :layout=>false and if else logic from controller actions,
i have custom mime type like phtml (plain html).
Mime::Type.register "text/phtml", :phtml
this format need to render the same html views, but only without layout. I complete this with this chunk of code in app. controller:
before_filter proc { |controller|
if params[:format] && params[:format]=='phtml'
controller.action_has_layout = false
controller.request.format = 'html'
end
}
First, this is ugly, second i can't any more control this format from controller in the way:
respond_to :phtml,:only=>:index
because it will always render view with requested format phtml.
is there a better solution? example? how can i alias view formats?
Thank a lot
You can use the layout method in your controller directly:
class ProductsController < ApplicationController
layout "product", :except => [:index, :rss]
end
Or to use no layout at all:
class ProductsController < ApplicationController
layout nil
end
Check out the guide for more info.
I haven't found better solution,only update to my previous example:
before_filter proc { |controller|
if params[:format] && params[:format]=='plain_html' && controller.collect_mimes_from_class_level.include?(:plain_html)
controller.action_has_layout = false
controller.request.format = 'html'
end
}
i added this line to check is a new format defined into our controller:
controller.collect_mimes_from_class_level.include?(:plain_html)
Now we can have full new format which will render our standard html vews rather the build new views for the new format.
This can be useful if we wont to share existing html code, but build different logic based on requested format.
For example, we can easily prepare our html content for print like:
class PagesController < ActionController::Base
layout 'print',:only=>:show
respond_to :plain_html,:only=>[:show]
def show
Page.find(1)
respond_with #page
end
end
And request will be like:
http://www.example.com/pages/1.plain_html
I hope that someone will find this useful.
If u have a better approach for doing this, please share with us.
Regards