How do I inherit default data from a module or class - ruby

I am working on an application to automate testing for SQL injection vulnerability. It is currently named Deft and is for a University project.
I want to be able to run tests from a command line, or an interactive console. I am coding several classes. (Deft::Cli, Deft::Console etc.)
Here's what I think I'd like to do.
module Deft
module App
attr_accessor :origin
#origin = { "host" => "localhost", "port" => "80" }
end
end
module Deft
class Console
include App
def initialize
puts origin
end
end
end
The example has been simplified, but the point is that the default values (and structure) get defined in the Deft::App module.
The problem as I can tell is that although methods.grep(/origin/) from inside a console instance does indeed give me ["origin=", "origin"] calling origin returns nil. Instead of the values I define in Deft::App. It makes sense that it doesn't work, but I don't know how to make it work.

Perhaps I'm taking the simplified example too literally, but one way to fix it is to get rid of the attr_accessor class method invocation and just make origin be the constant Origin or ORIGIN.

What about this?
module Deft
class DefaultConsole
attr_accessor :origin
def initialize
#origin = {'host' => 'localhost', 'port' => 80}
end
end
class Console < DefaultConsole
def initialize
super
puts origin
end
end
end
Deft::Console.new
# => {'host' => 'localhost', 'port' => 80}

Try like this:
module Deft
module App
attr_accessor :origin
def init
#origin = { "host" => "localhost", "port" => "80" }
end
end
end
module Deft
class Console
include App
def initialize
init
puts origin
end
end
end
Deft::Console.new

Thanks to everyone that added their input. I'm going to go ahead and answer my own question, this works as I had hoped.
module Deft
module App
##origin = { "host" => "localhost", "port" => "80" }
def origin ; ##origin ; end
def origin=(args) ; ##origin=(args) ; end
end
end
If anyone wants to copy and clean this up using attr_accesor then I'd be happy to edit this back into my question and accept their answer.

Related

Hanami parameters whitelisting

Following the hanami docs, in order to block a admin parameter inside an action, I can use the following configuration:
params do
required(:email).filled
required(:address).schema do
required(:country).filled
end
end
def call(params)
puts params[:email] # => "alice#example.org"
puts params[:address][:country] # => "Italy"
puts params[:admin] # => nil
end
But this does not work for nested parameters, i.e.:
params do
required(:email).filled
required(:address).schema do
required(:country).filled
end
end
def call(params)
puts params[:email] # => "alice#example.org"
puts params[:address] # => { country: "Italy", admin: true }
puts params[:address][:admin] # => true
end
I was able to solve this by using select to filter out the undesirable parameters with a private method, but this does not seems like the Hanami way. What would be the proper way to do this whitelisting of nested parameters?
I have never had this issue when using Hanami Validations. Within the app directory there should be a validations folder which should have the same directory structure as your controllers, views, templates etc. Your validation file should look something like this:
# apps/web/validations/users/create.rb
module Web
module Validations
module Users
class Create < Web::Action::Params
predicates Web::Validations::CommonPredicates
validations do
required(:email).filled
required(:address).schema do
required(:country).filled
end
end
end
end
end
end
And then your controller should set the params to be filtered through the validation:
module Web
module Controllers
module Users
class Create
include Web::Action
params Web::Validations::Users::Create
def call(params); end
end
end
end
end

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

Ruby structure for extendable handler/plugin architechture

I'm writing something that is a bit like Facebook's shared link preview.
I would like to make it easily extendable for new sites by just dropping in a new file for each new site I want to write a custom parser for. I have the basic idea of the design pattern figured out but don't have enough experience with modules to nail the details. I'm sure there are plenty of examples of something like this in other projects.
The result should be something like this:
> require 'link'
=> true
> Link.new('http://youtube.com/foo').preview
=> {:title => 'Xxx', :description => 'Yyy', :embed => '<zzz/>' }
> Link.new('http://stackoverflow.com/bar').preview
=> {:title => 'Xyz', :description => 'Zyx' }
And the code would be something like this:
#parsers/youtube.rb
module YoutubeParser
url_match /(youtube\.com)|(youtu.be)\//
def preview
get_stuff_using youtube_api
end
end
#parsers/stackoverflow.rb
module SOFParser
url_match /stachoverflow.com\//
def preview
get_stuff
end
end
#link.rb
class Link
def initialize(url)
extend self with the module that has matching regexp
end
end
# url_processor.rb
class UrlProcessor
# registers url handler for given pattern
def self.register_url pattern, &block
#patterns ||= {}
#patterns[pattern] = block
end
def self.process_url url
_, handler = #patterns.find{|p, _| url =~ p}
if handler
handler.call(url)
else
{}
end
end
end
# plugins/so_plugin.rb
class SOPlugin
UrlProcessor.register_url /stackoverflow\.com/ do |url|
{:title => 'foo', :description => 'bar'}
end
end
# plugins/youtube_plugin.rb
class YoutubePlugin
UrlProcessor.register_url /youtube\.com/ do |url|
{:title => 'baz', :description => 'boo'}
end
end
p UrlProcessor.process_url 'http://www.stackoverflow.com/1234'
#=>{:title=>"foo", :description=>"bar"}
p UrlProcessor.process_url 'http://www.youtube.com/1234'
#=>{:title=>"baz", :description=>"boo"}
p UrlProcessor.process_url 'http://www.foobar.com/1234'
#=>{}
You just need to require every .rb from plugins directory.
If you're willing to take this approach you should probably scan the filed for the mathing string and then include the right one.
In the same situation I attempted a different approach. I'm extending the module with new methods, ##registering them so that I won't register two identically named methods. So far it works good, though the project I started is nowhere near leaving the specific domain of one tangled mess of a particular web-site.
This is the main file.
module Onigiri
extend self
##registry ||= {}
class OnigiriHandlerTaken < StandardError
def description
"There was an attempt to override registered handler. This usually indicates a bug in Onigiri."
end
end
def clean(data, *params)
dupe = Onigiri::Document.parse data
params.flatten.each do |method|
dupe = dupe.send(method) if ##registry[method]
end
dupe.to_html
end
class Document < Nokogiri::HTML::DocumentFragment
end
private
def register_handler(name)
unless ##registry[name]
##registry[name] = true
else
raise OnigiriHandlerTaken
end
end
end
And here's the extending file.
# encoding: utf-8
module Onigiri
register_handler :fix_backslash
class Document
def fix_backslash
dupe = dup
attrset = ['src', 'longdesc', 'href', 'action']
dupe.css("[#{attrset.join('], [')}]").each do |target|
attrset.each do |attr|
target[attr] = target[attr].gsub("\\", "/") if target[attr]
end
end
dupe
end
end
end
Another way I see is to use a set of different (but behaviorally indistinguishable) classes with a simple decision making mechanism to call a right one. A simple hash that holds class names and corresponding url_matcher would probably suffice.
Hope this helps.

In selenium ruby tests can I combine the setup and teardown methods into one location for all my tests?

In my ruby Selenium Tests there is a lot of the same code in every test. How can I best share code between tests? For example my setup and teardown methods are the same in every file, how can I remove them from every file into one shared file or is that even possible?
def setup
#verification_errors = []
#selenium = Selenium::Client::Driver.new \
:host => "#$sell_server",
:port => 4444,
:browser => "#$browser",
:url => "http://#$network.#$host:2086/",
:timeout_in_second => 60
#selenium.start_new_browser_session
end
def teardown
#selenium.close_current_browser_session
assert_equal [], #verification_errors
end
I've tried putting setup in a shared module and a required file but both present different problems with inheritance of the other methods that need access to the #selenium object that is started. What would be a good design if there is one for sharing the code?
I'm not really sure what test framework you're using, but in rspec you could place it into your spec_helper file and just do a before(:each) / after(:each). I'd check the callback documentation for your framework of choice.
For test unit framework - it seems to work to create a SharedTest class to inherit from Test::Unit::Testcase with setup and teadown methods. Then just subclass the test files SharedTest. The only negative consequence I've found is I had to add a test_default method that does nothing in SharedTest to get it to work. If I name my test method test_default that overides it and seems ok, but not very descriptive...
sharedtest.rb
class SharedTest < Test::Unit::Testcase
def setup
#verification_errors = []
#selenium = Selenium::Client::Driver.new \
:host => "#$sell_server",
:port => 4444,
:browser => "#$browser",
:url => "http://#$network.#$host:2086/",
:timeout_in_second => 60
#selenium.start_new_browser_session
end
def teardown
#selenium.close_current_browser_session
assert_equal [], #verification_errors
end
def test_default
#puts self
end
end
T01_testcasename.rb
class Test_01_whatever < SharedTest
def test_default
#test code
end
I'm still open to better solutions but this seems to be working for me.

Is there a way to check if a record was built by another model in active record?

When using accepts_nested_attributes_for, I got stuck when having a validation which required the original to be present. The code will help clear up that sentence.
class Foo < ActiveRecord::Base
has_one :bar
accepts_nested_attributes :bar
end
class Bar < ActiveRecord::Base
#property name: string
belongs_to :foo
validates_presence_of :foo #trouble line!
end
#now when you do
foo = Foo.create! :bar_attributes => {:name => 'steve'}
#you get an error because the bar validation failed
I would like to write a validation that goes something like...
class Bar < ActiveRecord::Base
validates_presence_of :foo, :unless => :being_built_by_foo?
end
I am currently using rails3.beta4
Thank you
Alas I don't have an answer to this post, but the I came up with another way so I didn't need the validation.
Since bar should never be without a foo then any request to create a bar without a foo_id is an error. In the real example a foo is a project, and bar is a bid. It is a nested resource, but I wanted to give access to json apps to be able to query the info from the /bids location so the router looked like.
resources :bids
resources :projects do
resources: bids
end
and then I just had to make sure all html access used project_bids_path or form_for [:project,#bid] etc. This next part is largely untested but so far the desired behavior is there. I got the idea from Yehuda's post on generic actions http://yehudakatz.com/2009/12/20/generic-actions-in-rails-3/
#I'm sure there is a better way then map.connect
map.connect "projects/invalid_id", :controller => "projects", :action => "invalid_id"
resources :projects
resources :bids
end
#couple of changes from Yehuda
def redirect(*args, &block)
options = args.last.is_a?(Hash) ? args.pop : {}
path = args.shift || block
path_proc = path.is_a?(Proc) ? path : proc {|params| path % params }
status = options[:status] || 301
lambda do |env|
req = Rack::Request.new(env)
#Get both the query paramaters and url paramaters
params = env["action_dispatch.request.path_parameters"].merge req.params
url = path_proc.call(params.stringify_keys)
#Doesn't add the port back in!
#url = req.scheme + '://' + req.host + params
#content-type might be a bad idea, need to look into what happens for different requests
[status, {'Location' => url, 'Content-Type' => env['HTTP_ACCEPT'].split(',').first}, ['Moved Permanently']]
end
end
def bid_path
redirect do |params|
if params['project_id']
"/projects/#{params['project_id']}/bids/#{params['id']}"
else
'/projects/invalid_id'
end
end
end
match "bids", :to => bid_path
match "bids/:id", :to => bid_path
however, after doing all of this I most definitely don't think it worth it. I think nested_attributes breaks things and can be improved if that validation doesn't work, but after looking through the code for a little while I'm not sure exactly how to fix it or if it's worth it.
first of all, when using nested_attributes, you'll get the presence of the container. in the example: when you save Foo and there's also a nested form for Bar, then Bar is built by Foo.
I think there's no need to make this kind of validation if you're sure to use Bar only in contexts with Foo.
btw, try to write validation as follow (new preferred syntax for Rails3):
validates :foo, :presence => true
hope this helps,
a.

Resources