FasterCSV importer to DataMapper model - No rows inserted - ruby

I have a model (called Test):
property :id, Serial
property :title, String, :length => 255, :required => true
property :description, String, :length => 255, :required => true
property :brand, String, :length => 255, :required => true
property :link, String, :length => 255, :required => true
property :image_link, String, :length => 255, :required => true
property :price, String, :length => 255, :required => true
property :condition, String, :length => 255, :required => true
property :product_type, String, :length => 255, :required => true
I am importing data from a tab delimited file, using FasterCSV,
FasterCSV.foreach("test.txt", {:headers => true, :quote_char=>'"', :col_sep =>'/t'}) do |row_data|
row_data = Test.first_or_new(
'title' => :title,
'description' => :supplier,
'brand' => :brand,
'link' => :link,
'image_link' => :image_link,
'price' => :price,
'condition' => :condition,
'product_type' => :product_type
)
row_data.save
end
No errors appear, when I run the importer. Nothing appears inserted in SQLite table.
Am i missing something obvious? (The table exists within the target database, and the field names are the same as the headers from my file.

Update 2014/11/19: FasterCSV has been removed. Ruby standard library CSV should now be used intead. Just replace all occurrences of FasterCSV with CSV
There's two problem i guess
the delimiter you intended to use was rather "\t" than '/t'
you're not using the row_data to populate the datamapper object
This should work better:
FasterCSV.foreach("test.txt", {:headers => true, :quote_char=>'"', :col_sep =>"\t"}) do |row_data|
new_record = Test.first_or_new(
'title' => row_data['title'],
'description' => row_data['supplier'],
'brand' => row_data['brand'],
'link' => row_data['link'],
'image_link' => row_data['image_link'],
'price' => row_data['price'],
'condition' => row_data['condition'],
'product_type' => row_data['product_type']
)
new_record.save
end

Related

Watir: Passing dynamic selector

Is there a way to pass a dynamic set of options to a textarea element in browser?
options = {
:type => 'textarea',
:selector => ':id',
:field => 'id_of_textarea_field',
:value => 'Joe Salesperson'
}
browser.textarea(options[:selector] => options[:field]).set ''
Error received:
invalid attribute: ":id"
A similar thread is listed here (selecting elements using variables in ruby /watir) but no answer.
options = {
:type => 'textarea',
:selector => :id,
:field => 'id_of_textarea_field',
:value => 'Joe Salesperson'
}
You can just pass the identifier, no need for quotes.
2017-01-03, Updating with a use case. Here is the declaration of the method I'm using and the call. The actual code is much more verbose and contains different validations than what I've pasted here. In the example, you'll notice a simple switch block which sets the appropriate information based on the element type passed (specifically text areas, text fields, and select elements).
def validateInput(options = {})
success = true
begin
case options[:type]
when 'textarea', 'text_field'
Watir::Wait.until{$browser.textarea(options[:selector] => options[:field]).present?}
$browser.textarea(options[:selector] => options[:field]).set options[:value]
when 'select'
$browser.select_list(options[:selector] => options[:field]).select_value options[:value]
else
puts "in else"
end
end
rescue => e
$message.push("Failed to validate '#{options[:field]}' field. #{e}")
success = false
end
return success
end
validateInput({
:type => 'textarea',
:selector => :id,
:field => 'order_approval_comment_name',
:value => 'Joe Salesperson'
})

Can't get value from nested pair in Omniauth hash.

I'll try to keep this simple, my previous wording was maybe a bit too verbose:
Here is the example Omniauth hash: https://github.com/mkdynamic/omniauth-facebook
I can access and save some values from this but not others. The field is writable, so I know its just my syntax (beginner, sorry!)
{
:provider => 'facebook',
:uid => '1234567',
:info => {
:nickname => 'jbloggs',
:email => 'joe#bloggs.com',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:image => 'http://graph.facebook.com/1234567/picture?type=square',
:urls => { :Facebook => 'http://www.facebook.com/jbloggs' },
:location => 'Palo Alto, California',
:verified => true
},
:credentials => {
:token => 'ABCDEF...', # OAuth 2.0 access_token, which you may wish to store
:expires_at => 1321747205, # when the access token expires (it always will)
:expires => true # this will always be true
},
:extra => {
:raw_info => {
:id => '1234567',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:link => 'http://www.facebook.com/jbloggs',
:username => 'jbloggs',
:location => { :id => '123456789', :name => 'Palo Alto, California' },
:gender => 'male',
:email => 'joe#bloggs.com',
:timezone => -8,
:locale => 'en_US',
:verified => true,
:updated_time => '2011-11-11T06:21:03+0000'
}
}
}
I can do this to get gender and save it.
location:auth.extra.raw_info["gender"]
Obviously though I dont want to save gender to location. I want to get "Palo Alto" and save it. But this doesn't work.
location.auth.extra.raw_info["location"]["name"]
What am I doing wrong? When I try it in console, I'm able to get the value.
try this
location.auth.extra.raw_info.location.name
or this
location.auth.extra.raw_info[:location][:name]
Yeah, what you suggested was what I was trying...and it turns out we were right but FB had changed how that hash was set up so it wasn't working. Lesson learned: subscribe FB's notifications next time :)

Create multi-dimensional array or hash in ruby from JSON

I am using Rhomobile and trying to dynamically build a hash for the id and title of the buttons has of the Alert.show_popup, but am not quite getting it. What I want the end result to be, in effect, is:
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => [
{'id' => '1', 'title' => 'Address 1'},
{'id' => '2', 'title' => 'Address 2'},
{'id' => '3', 'title' => 'Address 3'},
{'id' => '4', 'title' => 'Address 4'}
],
:callback => url_for(:action => :on_addressidentified_popup)
}
)
I've tried a few methods, but none have worked (build a string that looks like a hash and try_convert, etc.). Here was the latest one I tried which seemed close, but yet still far away:
nearbyaddresses = Rho::JSON.parse(#params['body'])
h = {}
nearbyaddresses.each do |location|
h[intIndex] = {}
h[intIndex][:id] = intIndex.to_s
h[intIndex][:title] = location["Address"].to_s
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => h,
:callback => url_for(:action => :on_addressidentified_popup)
}
)
Any ruby wizards here that can help me out?
How about
nearby_addresses_list = Rho::JSON.parse(#params['body'])
buttons_list = nearby_addresses_list.collect.each_with_index {|address, i|
{'id' => i, 'title' => address} #not sure if you need to dig into this at all.
}
This should leave buttons_list with this value
[{'id' => 0, 'title' => nearby_addresses_list[0]},
{'id' => 1, 'title' => nearby_addresses_list[1]}
{'id' => 2, 'title' => nearby_addresses_list[2]}
{'id' => 3, 'title' => nearby_addresses_list[3]}]
If you want the id's to start with 1, change the body of the collect statement to {'id' => i+1, 'title' => address}
Then just add buttons_list in as the value for the key :buttons.
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => buttons_list,
:callback => url_for(:action => :on_addressidentified_popup)
})
If you're seeing weirdness between the desired output you mentioned first and the code you said was close, is it perhaps that you used symbols for the keys in your code (:id), and strings in your desired output ("id") ?
Here's how I addressed the issue. Works like a charm...
intIndex = 0
nearbyaddresses = Rho::JSON.parse(#params['body'])
##nearbyAddresses = nearbyaddresses
button_array = []
nearbyaddresses.each do |location|
opt = {'id' => intIndex.to_s, 'title' => location["Address"] }
button_array << opt
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => button_array,
:callback => url_for(:action => :getselectedaddress)
}
)

Not null fields for ActiveAttr

I'm having issues enforcing a field to not be nil within ActiveAttr::Model.
Is there an elegant way of enforcing this constraint within the model instead of defining it in the controller? Or am I testing incorrectly for the scenario?
Model:
class Message
include ActiveAttr::Model
attribute :name, :presence => true, :allow_nil => false, :allow_blank => false
attribute :email, :presence => true
attribute :content, :presence => true
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
end
RSpec:
module MessageSpecHelper
def valid_message_attributes
{
:name => "Walter White",
:email => "walter#hailtheking.com",
:content => "I am the one who knocks"
}
end
end
it "should have error on name (alternate with nil)" do
#message.attributes = valid_message_attributes.except(:name => nil)
#message.should have(1).error_on(:name)
end

Creating a class and adding methods dynamically in Ruby

How do I go about creating a new class and adding a few methods to it without resorting to "eval"?
Here's what I'm trying to do; I'd like to transform this structure:
obj = [
{
:scope => 'account',
:fields => [
{ :title => 'title', :length => 64, :required => true },
{ :title => 'email', :length => 256, :required => true, :type => 'email' }
],
:before_save => Proc.new{
#do something here
},
},
{
:scope => 'product',
:fields => [
{ :title => 'title', :length => 64, :required => true },
{ :title => 'description', :length => 256, :required => true },
{ :title => 'cost', :required => true, :type => 'decimal' }
]
},
]
into this:
class Account
include DataMapper::Resource
property :id, Serial
property :title, String, :length => 64, :required => true
property :email, String, :length => 256, :required => true
def before_save
#do something here
end
end
...
Thanks!
As Andrew already said, there are different ways to create class dynamically. This could be one of them:
Say you start with one DM model (haven't used DM, taking the first one from the docs):
class Post
include DataMapper::Resource
property :id, Serial # An auto-increment integer key
property :title, String # A varchar type string, for short strings
property :body, Text # A text block, for longer string data.
property :created_at, DateTime # A DateTime, for any date you might like.
end
and you want to create it dynamically, from a metadata given in a hash of the form
{:ClassName => {:field1 => :Type1, :field2 => :Type2 ...}}
You could do:
require 'data_mapper'
models = {:Post => {
:id => :Serial,
:title => :String,
:body => :Text
}}
models.each do |name, fields|
klass = Class.new do
include DataMapper::Resource
fields.each do |field_name, field_type|
property(field_name, const_get(field_type))
end
end
Object.const_set(name, klass)
end
Key methods:
Class.new
Module#const_set
If you want to look at a real-world example, please consult the code in this library: https://github.com/apohllo/rod/blob/v0.7.x/lib/rod/model.rb#L410

Resources