How does rescue_action in Rails3 work? - ruby

I would like to implement this
class SecurityTransgression < StandardError; end
def create
raise SecurityTransgression unless ...
end
class ApplicationController < ActionController::Base
def rescue_action(e)
case e
when SecurityTransgression
head :forbidden
end
end
end
from the this blogpost.
The problem is it does not work. I dont see a forbidden page but standard Rails error page "SecurityViolation in MyController#action". I digged that some rescue_action methods works only in the production mode. I tried that and it is the same. No change.
My question: is there any good documentation of the rescue_action method (and others)? Does this work under Rails 3.0? Because it seems this is some old

Take a look at rescue_from at the API documentation.

The rescue_action method is normally called internally with the #_env hash being passed as a parameter. The method is expecting the Exception instance to exist within the "action_dispatch.rescue.exception" key.
If you must use the rescue_action method directly, you can do the following:-
#_env[ "action_dispatch.rescue.exception" ] = exception
rescue_action( #_env )
or even more simple:-
rescue_action( { "action_dispatch.rescue.exception" => exception } )

Related

private method `new' called for MyReminderMailer:Class

In a controller, i have:
mailer = MyReminderMailer.new
the mailer looks like this:
class MyReminderMailer < ActionMailer::Base
def change_email
mail(
from: default_from,
to: default_to,
subject: "..."
)
end
def default_from
return '...'
end
def default_to
return '...'
end
end
but got error: private method `new' called for MyReminderMailer:Class
ActionMailer::Base has a rather goofy and unintuitive API. Much like controllers, you never explicitly create instances of your mailers. Instead, you interact with them as classes. new is marked private in ActionMailer::Base, and method calls on the class are subsequently routed through method_missing to a new instance of itself. Like I said, unintuitive.
Have a look at the guides and api docs for more information on the correct usage of ActionMailer.
Ruby does not allow to call private method in normal way.
You can call it with send method
SomeClass.send :method_name
#in your case
MyReminderMailer.send :new
And you don't need ActionMailer object.
To send mail just use the method as like class method.
MyReminderMailer.change_email.deliver
Hope this can help you.

rails method chaining context

I have what is probably a basic Q, but it appears complex in the setup. I have a module that has some classes. One class contains methods for API calls. Other classes describe a server. Dev for instance has its attributes. The server classes inherit the class that contains all the API calls. I use an instance of the server class to use one of these methods and then apply EventMachine methods to it. Here's a subset of a server class:
class PulseDev < ApiMethods
def base_uri
"http://myserver.com/api"
end
end
And an action in the methods class:
Class ApiMethods
def get_json_api_post_response(url, post_obj={})
http = EM::Synchrony.sync EventMachine::HttpRequest.new(self.base_uri+"#{url}").post(:body => post_obj)
process_response self.class.post(url, :body => post_obj).body
end
def process_response(result)
response = ActiveSupport::JSON.decode(result)
if response["code"].to_i == 200
ToolResult.new(true, response["result"], 200)
else
ToolResult.new(false, response["result"], response["code"])
end
end
end
Class ToolResult < Struct.new(:success, :result, :code)
end
And my invocation of it in the controller:
http = ApiMethods::Dev.new.get_json_api_post_response('/handshake', #j)
OK, my error is undefined method `post' for ApiMethods::PulseDev:Class
and it points to the post in my get_json_api_post_response method.
My question is: I get that it's within the context of the ApiMethods::Dev which is why self.base_uri works but how should I handle the post inside that process_response method so that it's tied to EventMachine? Is there something about method chaining I'm not seeing? In the error output I can verify that http is showing the EventMachine object so the new method seems to be working. Thanks for your time, sam
The answer is to look more carefully at the error msg. The process_response method is the one actually calling the EventMachine method and processing its :body. So it was written with an unneeded call.

What are callback classes in ActiveRecord::Base in Rails

Can some one explain 16 Callback classes in this guide http://guides.rubyonrails.org/active_record_validations_callbacks.html
Ok i think i understand your problem :
The after_destroy method in PictureFileCallbacks will be auto-magically called by rails :
When rails destroys your PictureFile object, it will instantiate a PictureFileCallbacks object and try to run an after_destroy method in it.
Everything works by convention, if you follow the naming properly everything will work out of the box.
Try it on a dummy project, and if you have some trouble making this work come back with some code to show.
everything works by convention, you can try the following example:
#generate PictrueFile model with name attribute and generate seed
rails g model PictureFile name:string
#seeds.rb
3.times do |i|
PictureFile.create(name: "name#{i}")
end
#create picture_file.rb and picture_file_callbacks.rb in model directory
#picture_file_callbacks.rb
class PictureFileCallbacks
def after_destroy(picture_file)
PictureFile.create(name: "demo")
end
end
#picture_file_callbacks.rb
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks.new
end
execute the command in rails c
PictureFile.first.destroy
PictrueFile.pluck(:name) #=>["name1", "name2", "demo"]

ruby, no method error

I am receiving the following error when running my below ruby script:
s3parse.rb:12:in `block in <class:AccountLog>': undefined method `extract_account_id' for AccountLog:Class (NoMethodError)
I dont think it should be a class method, is there a reason its not taking my method into account?
class AccountLog
attr_accessor :bytes, :account_id, :date
def extract_account_id(line)
line.match(%r{accounts/(\d+)}).captures.join.to_i
end
s3log = File.open('vidcoder.txt').each do |line|
account_log = AccountLog.new
account_log.date = line.match(%r{\[[^:]*}).to_s.delete"[" #need to finish this regex to make it work
account_log.account_id = extract_account_id(line)
account_log.bytes = line.match(%r{^.*\s+HTTP.*\s+-\s+(\d+)\s+}).captures.join.to_i
puts "\n"
puts "The api request on #{account_log.date} was fromm account number #{account_log.account_id} and the bytes were #{account_log.bytes}"
end
end
def extract_account_id will define an instance method.
In the way you call it, you need a class method instead.
Define it like this:
def self.extract_account_id(line)
or, as you already have an AccountLog instance, use it to call extract_account_id:
account_log.account_id = account_log.extract_account_id(line)
Please note that with second way you do not need to alter method definition, just call extract_account_id via account_log instance.
And i guess you would want to put s3log = File... outside class definition.
Or use a constant instead: S3log = ...
Then you'll can access it as AccountLog::S3log
Is there any reason you don't think it should be a class method? You are using it in the context of a class method and that's why it it's saying no such method for class AccountLog.
If you name your method as self.extract_account_id(line) I'm sure it will work.
From what you are trying to do I think this is what you are looking for?
class AccountLog
attr_accessor :bytes, :account_id, :date
def self.extract_account_id(line)
line.match(%r{accounts/(\d+)}).captures.join.to_i
end
end
s3log = File.open('vidcoder.txt').each do |line|
account_log = AccountLog.new
account_log.date = line.match(%r{\[[^:]*}).to_s.delete"[" #need to finish this regex to make it work
account_log.account_id = extract_account_id(line)
account_log.bytes = line.match(%r{^.*\s+HTTP.*\s+-\s+(\d+)\s+}).captures.join.to_i
puts "\n"
puts "The api request on #{account_log.date} was fromm account number #{account_log.account_id} and the bytes were #{account_log.bytes}"
end
While you could take the class method approach, there seems to be a little more going on.
You should put the extraction logic in a method in itself rather than let it hangout in your class. Then outside of the class, have an instance of AccountLog where you can call on the methods for log and account id extraction. At that point you can do something with those values.
Class method or not is a detail we can explore after the class is a bit more clean I think.

Rails routing: Giving default values for path helpers

Is there some way to provide a default value to the url/path helpers?
I have an optional scope wrapping around all of my routes:
#config/routes.rb
Foo::Application.routes.draw do
scope "(:current_brand)", :constraints => { :current_brand => /(foo)|(bar)/ } do
# ... all other routes go here
end
end
I want users to be able to access the site using these URLs:
/foo/some-place
/bar/some-place
/some-place
For convenience, I'm setting up a #current_brand in my ApplicationController:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_brand
def set_brand
if params.has_key?(:current_brand)
#current_brand = Brand.find_by_slug(params[:current_brand])
else
#current_brand = Brand.find_by_slug('blah')
end
end
end
So far so good, but now I must modify all *_path and *_url calls to include the :current_brand parameter, even though it is optional. This is really ugly, IMO.
Is there some way I can make the path helpers automagically pick up on #current_brand?
Or perhaps a better way to define the scope in routes.rb?
I think you will want to do something like this:
class ApplicationController < ActionController::Base
def url_options
{ :current_brand => #current_brand }.merge(super)
end
end
This method is called automatically every time url is constructed and it's result is merged into the parameters.
For more info on this, look at: default_url_options and rails 3
In addition to CMW's answer, to get it to work with rspec, I added this hack in spec/support/default_url_options.rb
ActionDispatch::Routing::RouteSet.class_eval do
undef_method :default_url_options
def default_url_options(options={})
{ :current_brand => default_brand }
end
end

Resources