In Ruby on Rails, where does one put the code from this snippet in http://gist.github.com/376389? I want to extend ActiveRecord::Errors with the code that's available there so I can merge error messages.
Is this something for ApplicationController? or for lib?
Paste from github.com
# monkey patch gleaned from http://dev.rubyonrails.org/attachment/ticket/11394/merge_bang_errors.patch
module ActiveRecord
class Errors
def merge!(errors, options={})
fields_to_merge = if only=options[:only]
only
elsif except=options[:except]
except = [except] unless except.is_a?(Array)
except.map!(&:to_sym)
errors.entries.map(&:first).select do |field|
!except.include?(field.to_sym)
end
else
errors.entries.map(&:first)
end
fields_to_merge = [fields_to_merge] unless fields_to_merge.is_a?(Array)
fields_to_merge.map!(&:to_sym)
errors.entries.each do |field, msg|
add field, msg if fields_to_merge.include?(field.to_sym)
end
end
end
end
You can just drop that into any ruby file in your initializers directory (create a new one, name it whatever you want). Rails runs all of the files in there every time it is booted, and will extend Errors at that time.
This question is stale but if you want to do something similar in rails 3.x you can drop this in a file in your config/initializers/ directory:
# monkey patch gleaned from http://dev.rubyonrails.org/attachment/ticket/11394/merge_bang_errors.patch
module ActiveModel
class Errors
def merge!(errors, options={})
return if errors.blank? || errors.first.size < 2
fields_to_merge = if only=options[:only]
only
elsif except=options[:except]
except = [except] unless except.is_a?(Array)
except.map!(&:to_sym)
errors.entries.map(&:first).select do |field|
!except.include?(field.to_sym)
end
else
errors.entries.map(&:first)
end
fields_to_merge = [fields_to_merge] unless fields_to_merge.is_a?(Array)
fields_to_merge.map!(&:to_sym)
errors.entries.each do |field, msg|
add field, msg if fields_to_merge.include?(field.to_sym)
end
end
end
end
Related
The following code is meant to determine which subclass of itself to execute. It cycles through everything in the ObjectSpace to find subclasses and then execute the correct one from there. In rails, this does not work, because classes in the library folder are not in the ObjectSpace. What is a way to search through a specific folder for subclasses?
def execute
ObjectSpace.each_object(Class).select do |klass|
if (klass < self.class)
klass.designations.each do |designation|
if (designation.downcase.capitalize == #action.downcase.capitalize)
command = klass.new(#sumo_params)
command.execute
end
end
end
end
end
OR -- Is there a superior solution to this problem that you would recommend?
I'd say use a module for this. So, this would make you code something like the following:
lib/base_methods.rb
module BaseMethods
def self.included(base)
##classes_including ||= []
##classes_including << base
end
def do_whatever
##classes_including.each do |class|
#....
end
end
end
lib/class_1.rb
class Class1
include BaseMethods
end
I took the easy way out for now (iterating through an array of string values):
def execute
#descendants.each do |descendant|
klass = descendant.downcase.capitalize.constantize
if (klass < self.class)
klass.designations.each do |designation|
if (designation.downcase.capitalize == #action.downcase.capitalize)
command = klass.new(#sumo_params)
command.execute
end
end
end
end
end
I am trying to limit who can access the csv/json/... exports in ActiveAdmin based on the field 'limited'. I'd like to a) hide the links and b) return nothing at all if the path were to get hit anyway
I tried the following:
index downloads_links: !current_admin_user.limited? do
# ...
end
as well as
csv do
return if current_admin_user.limited?
# ...
end
I also briefly tried using procs and lambda's but that's probably not the solution here either?
Neither appear to work and are giving me nomethoderrors on ActiveAdmin::DSLResource and ActiveAdmin::CSVBuilder respectively
Any tips are welcome, thank you
i was able to achieve this with a simple monkey patch, but i was using cancan. cancan helper method 'can?' worked fine, but i wasn't testing the 'current_admin_user'. please, try it
module ActiveAdmin
module Views
class PaginatedCollection
def build_download_format_links(formats = self.class.formats)
params = request.query_parameters.except :format, :commit
links = formats.map { |format| link_to format.to_s.upcase, params: params, format: format }
unless current_admin_user.limited?
div :class => "download_links" do
text_node [I18n.t('active_admin.download'), links].flatten.join(" ").html_safe
end
end
end
end
end
end
upd:
i've tried with current_admin_user, and it worked.
also if you need to limit the formats, you can redefine formats method it this module, using your 'limited' method:
module ActiveAdmin
module Views
class PaginatedCollection
def formats
if current_admin_user.limited?
#formats ||= [:csv] # anything you need for limited users
else
#formats ||= [:csv, :xml, :json]
end
#formats.clone
end
end
end
end
I am using jruby to run bunch of ruby scripts, though I am using pure ruby part of it.
It sometimes gets difficult to follow from output what exactly is happening or where exactly something went wrong.
I wanted to get something like this in my std out for every method:
entered in method A
out of method A
Now I can surely go and put those comments in every method ..which feels very wrong. Is there a way to run ruby in a little verbose more to get this information in my log. Hopefully I would avoid using a lot of gems etc .. since these are on some managed servers and I will have to spend some time to just get more s/f on it. Hoping something would be avail as part of jruby itself
Thanks!
You could use this code:
module InOutHook
module ClassMethods
def setup_hooks(*syms)
syms.each do |sym| # For each symbol
str_id = "__#{sym}__hooked__"
unless private_instance_methods.include?(str_id)
alias_method str_id, sym # Backup original method
private str_id # Make backup private
define_method sym do |*args| # Replace method
puts ">>> #{self.class}\##{sym} >>>"
ret = __send__ str_id, *args # Invoke backup
puts "<<< #{self.class}\##{sym} >>>"
ret
end
end
end
end
end
def InOutHook.included(base)
base.extend(ClassMethods)
end
end
class TestClass
def test1
puts "test!"
end
def test2(v)
puts "Value is #{v}"
end
include InOutHook
setup_hooks(:test1, :test2)
end
# works on existing classes too:
class Array
include InOutHook
setup_hooks(:[])
end
tc = TestClass.new
tc.test1
tc.test2(10)
ary = [1,2,3]
puts ary[1..2]
In case you want to add a hoot to every method, just add a splat asterisk:
setup_hooks(*[].methods)
I want to override how rails creates a view *.html.erb
In ActionView package I already Tried to do it. Doing it
class ERB
class Compiler # :nodoc:
..
class Buffer # :nodoc:
def compile(s)
...
#It stores in a buffer each ruby chunk in the views inside of a Buffer.
end
end
end
...
# Here it is where is called compile method.
# The thing is that if my view is made up of several *.html.erb files such as partials this method will be invoked each time.
#INVOKED PER EACH html.erb file
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
puts ">>> initialize"
#safe_level = safe_level
# ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.update(:default => "%d %b %Y")
compiler = ERB::Compiler.new(trim_mode)
# raise "need a block"
# ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.update(:default => nil)
set_eoutvar(compiler, eoutvar)
#src = compiler.compile(str)
#filename = nil
end
end
end
I would like to find out when the process on the bottom starts. I mean which class, file, etc I have to override to see where Rails starts invoking all html.erb for an specific view.
I think that I should be here:
require 'delegate'
require 'optparse'
require 'fileutils'
require 'tempfile'
require 'erb'
module Rails
module Generator
module Commands
class Create
# Generate a file for a Rails application using an ERuby template.
# Looks up and evaluates a template by name and writes the result.
#
# The ERB template uses explicit trim mode to best control the
# proliferation of whitespace in generated code. <%- trims leading
# whitespace; -%> trims trailing whitespace including one newline.
#
# A hash of template options may be passed as the last argument.
# The options accepted by the file are accepted as well as :assigns,
# a hash of variable bindings. Example:
# template 'foo', 'bar', :assigns => { :action => 'view' }
#
# Template is implemented in terms of file. It calls file with a
# block which takes a file handle and returns its rendered contents.
def template(relative_source, relative_destination, template_options = {})
puts "EEEEEEEEEEEEEEEEEEEEEe"
file(relative_source, relative_destination, template_options) do |file|
# Evaluate any assignments in a temporary, throwaway binding.
vars = template_options[:assigns] || {}
b = template_options[:binding] || binding
vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
# Render the source file with the temporary binding.
ERB.new(file.read, nil, '-').result(b)
end
end
end
end
end
end
But I do not find any trace from the puts method.
All renaming are placed in a file called /lib/*_extensions.erb and in /config/initializers/extensions.rb I have the next:
Dir[File.dirname(__FILE__) + "/../../lib/*_extensions.rb"].each do |fn|
require fn
end
I do not want to reveal why I am doing this.
Thanks
I wanted to use a before_render it does not exist at least in Rails 2.3.4.
So if you want to do it, I did as the next:
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
# Scrub sensitive parameters from your log
# filter_parameter_logging :password
protected
def render(options = nil, extra_options = {}, &block) #:doc:
puts "BEFORE render"
puts "Setting %H:%M:%S"
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:default => "%H:%M:%S")
# call the ActionController::Base render to show the page
super
puts "AFTER render"
puts "Resetting"
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:default => nil)
end
end
I'm defining my own AR class in Rails that will include dynamically created instance methods for user fields 0-9. The user fields are not stored in the db directly, they'll be serialized together since they'll be used infrequently. Is the following the best way to do this? Alternatives?
Where should the start up code for adding the methods be called from?
class Info < ActiveRecord::Base
end
# called from an init file to add the instance methods
parts = []
(0..9).each do |i|
parts.push "def user_field_#{i}" # def user_field_0
parts.push "get_user_fields && #user_fields[#{i}]"
parts.push "end"
end
Info.class_eval parts.join
One nice way, especially if you might have more than 0..9 user fields, would be to use method_missing:
class Info
USER_FIELD_METHOD = /^user_field_(\n+)$/
def method_missing(method, *arg)
return super unless method =~ USER_FIELD_METHOD
i = Regexp.last_match[1].to_i
get_user_fields && #user_fields[i]
end
# Useful in 1.9.2, or with backports gem:
def respond_to_missing?(method, private)
super || method =~ USER_FIELD_METHOD
end
end
If you prefer to define methods:
10.times do |i|
Info.class_eval do
define_method :"user_field_#{i}" do
get_user_fields && #user_fields[i]
end
end
end
Using method_missing is very difficult to maintain and unnecessary. The other alternative using define_method is better but leads to poorly performing code. The following 1 liner is all you need:
class Info
end
Info.class_eval 10.times.inject("") {|s,i| s += <<END}
def user_field_#{i}
puts "in user_field_#{i}"
end
END
puts Info.new.user_field_4