Ruby/Watir - storing watir objects in hash? - ruby

I'm new to Ruby, and I LOVE IT.
Playing around with Watir-Webdriver.
I want to store the reference to watir objects in a hash and save it to disk, WITHOUT having first defined the #browser variable.
For example
elements = {
:home => #browser.a(:href => /home.php/),
:photo => #browser.img(:id => "photo"),
:about => #browser.a(:href => /about.php/)
}
so that further I can do something like:
el = elements
el[:home].click
el[:photo].wait_until_present
el[:about].click
obviously this works if I define #browser at the very beginning..
#browser = Watir::Browser.new
but what if I want to store the 'elements' hash as YAML in a file?
Should I store the values as quoted strings and eval them on the fly? like
elements = {
:home => "#browser.a(:href => /home.php/)",
# etc...
}
# store elements as YAML file...
# load elements from YAML file
el = YAML::load_file "elements.yml"
eval(el[:home]).click
eval(el[:photo].wait_until_present
# etc...
is there a better way to do this?

Build a Class to provide access to #browser based on your YAML config.
Modify your elements structure to include the data you need rather than code. Consider this a config hash/file of sorts for your new Class.
elements = {
:home => { :tag => "a", :select => { :href => /home.php/ } },
:photo => { :tag => "img", :select => { :id => "photo" } },
:about => { :tag => "a", :select => { :href => /about.php/ } }
}
Build a class to load the elements YAML file and provide access to what you need from #browser based on what is loaded.
class WatirYamlBrowserSelect
# To store your config and browser.
attr_accessor :elements, :browser
def initialize elements_yaml_file
#elements = YAML.load_file elements_yaml_file
end
# Retrieve a configured element from Watir Browser.
def element name
#browser.send( #elements[name][:tag], #elements[name][:select] )
end
end
Then when you need to use it
# Create an instance of your selector.
s = WatirYamlBrowserSelect.new( "elements.yaml" )
# Add the browser when you have it
s.browser #browser
# Access the #browser elements
s.element :home
s.element :photo
s.element :about

Alister Scott's blog as well as its code in github was the template I used for building all the page objects for a few projects. I think it should solve the repetition issues you described. It also solves the problem of maintaining too many variables for too many pages of objects and keeps objects organized by page and not in a more complex data structure, especially when the number of objects increases.
http://watirmelon.com/2011/06/07/removing-local-page-references-from-cucumber-steps/
http://watirmelon.com/2012/06/04/roll-your-own-page-objects/
https://github.com/alisterscott/wmf-custom-page-object

Related

Multiple joins mocks and Rspec

I'm trying to mock this statement, but I can't find anything on the internet to help me:
someone_ids = Office.join(:address, id: :address_id)
.join(:office_someone, id: :id)
.pluck(:someone_id)
Here is the spec that I'm using:
expect(Office).to receive(:join)
.with(:office_someone, { :id => :id })
.with(:address, { :id => :address_id })
.and_return([1])
Does anybody know how to mock multiple join? I'm using Sequel.
Previously RSpec had a stub_chain method that allowed you to do something like that easily, however it was removed because it encouraged bad practices, and now you'll have to stub each response manually:
office = instance_double(Office)
expect(Office).to receive(:join)
.with(:address, { :id => :address_id })
.and_return(office)
expect(office).to receive(:join)
.with(:office_someone, { :id => :id })
.and_return(office)
expect(office).to receive(:pluck).with(:someone_id).and_return([1])
Which if its a code that you find yourself repeating too much will made you think about refactoring it, which in the end is one of the reasons people do testing: "If its hard to test, it might not be well designed"

Creating new Tags

Just wondering if it is possible to create a new GIT tag using Rugged. if so, an example would be greatly appreciated.
I'm basically just trying to create/move/delete tags on commit oids.
You can see some examples in test/tag_test.rb:
#repo = sandbox_init("testrepo.git")
#tag = #repo.tags.create('annotated_tag', "5b5b025afb0b4c913b4c338a42934a3863bf3644", {
:message => "test tag message\n",
:tagger => { :name => 'Scott', :email => 'schacon#gmail.com', :time => Time.now }
})
For deletion, see test/reference_test.rb:
tag = #repo.tags["test"]
#repo.references.delete(tag)
refute #repo.references.exists?("refs/tags/test")
The OP Chris Portman points out in the comments that:
The create/delete methods are actually part of the TagCollection class.
Same with branches and the BranchCollection class.

How to persist ransack searching parameters

I'm using ransack for searching users based on their company and active/inactive parameter. This works well when used individually, but I want to make use of both simultaneously. For example, if I select company first and then select active/inactive user, then the company name should persist.
Second, is there a facility in ransack to keep both values persisted when I click back or again on users?
UPDATE :
This is my view:
= search_form_for #search, url: search_users_path, method: :post, html: { class: 'sort' } do |f|
= f.label 'company:'
= f.select :company_id_eq,
Company.where('is_inactive = false').collect {|c| [ c.name, c.id ] },
{:include_blank => 'All company users'}, :'data-remote' => true, class: 'searchSelect searchUserSelect'
%div.sort_users
= f.label 'sort Users:'
= f.select :deleted_eq,
[raw("<option value= 0 selected=#{session[:deleted]}>Active Users</option><option value= 1>Inactive Users</option>")],
{}, :'data-remote' => true, class: 'searchSelect searchUserSelect', style: "width: 205px;"
This is my code in controller
#search = User.search(params[:q])
#users = #search.result.includes(:company).order("companies.name, last_name").page(params[:page]).per(20)
About filters persistence, I'm using the following before_action in ApplicationController:
def get_query(cookie_key)
cookies.delete(cookie_key) if params[:clear]
cookies[cookie_key] = params[:q].to_json if params[:q]
#query = params[:q].presence || JSON.load(cookies[cookie_key])
end
Then, say for an Intervention model, I have the following:
class InterventionsController < ApplicationController
before_action only: [:index] do
get_query('query_interventions')
end
def index
#q = Intervention.search(#query)
#interventions = #q.result
end
end
That way, if interventions_path is called without the q param, cookies['query_interventions'] is checked to access last persisted query. But when interventions_path is called with the q param, this new query is used and persisted for later use.
Also, if interventions_path is called with the clear param, the cookie is deleted.
Note this would raise a CookieOverflow exception if more than 4k are stored, but this is between 1024 and 4096 UTF-8 characters and it is usually ok. If not, you should use other kind of session storage.

Issues with Carrierwave in Rails 3.1.0

I'm trying to attach a file "attachment" to my upload model. The attachment field in my db after creation is nil, and links link #upload.attachment.url just redirect to a parent object. Maybe I'm doing something wrong? I haven't used Carrierwave before.
# Model
require 'carrierwave/orm/activerecord'
class Upload < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
end
Went with the basics for for the attachment field
# Form
= form_for #upload, :html => { :multipart => true } do |f|
%br
= f.file_field :attachment
And more basics with the controller:
def create
#upload = Upload.new(params[:upload])
#upload.attachment = params[:file]
if #upload.save
redirect_to #upload
end
end
I'm not getting any errors in my console, but the :attachment string on the student model is always nil.
Thanks!
Why u have added the line
#upload.attachment = params[:file]
remove it. it will work. attachment string is null because there is not params file in the form.

Editing records with SQLite, DataMapper, and Sinatra

I'm in the process of learning Sinatra and DataMapper. To do so, I've been playing with a "customer database" project.
Creating and deleting records is trivial and now I'm working on editing records. So far I've managed to piece together a form in my views and a couple of routes that I thought would edit a record. Here's some code to illustrate my issue:
My edit.erb view: http://gist.github.com/308405
My edit/update routes:
get '/edit/:acct' do
#title = "Edit Client Data"
#client = HE_Backend.get(params[:acct])
erb :edit
end
post '/update/:acct' do
client = HE_Backend.get(params[:acct])
client.attributes = {
:name => params['client']['name'],
:company => params['client']['company'],
:street => params['client']['street'],
:state => params['client']['state'],
:zip => params['client']['zip'],
:phone => params['client']['phone'],
:fax => params['client']['fax'],
:website => params['client']['website'],
:order_date => params['client']['order_date'],
:payment_date => params['client']['payment_date'],
:monthly => params['client']['monthly'],
:setup => params['client']['setup'],
:details => params['client']['details'],
:notes => params['client']['notes'],
:status => params['client']['status'],
}
if client.save
redirect "/show/#{client.acct}"
else
redirect('/list')
end
end
It looks like the "client.save" portion of the route is returning false, because I'm getting redirected to "/list" each time. If I use the #update method rather than #save, DM complains about "dirty records".
Anyone have any ideas as to what I'm doing wrong or can you point me to examples for editing records in SQLite with DataMapper and Sinatra?
Thanks!
This turned out to be a validations issue. If I don't have validations in place and put data types other than what's in my model in those fields, the #save method apparently returns false.

Resources