I recently started using kirbybase in ruby, but I ran into a problem using the if statement with a result set. Here's a semplified code that seems to have this problem:
require 'kirbybase'
db = KirbyBase.new
if db.table_exists?(:database)
db.drop_table(:database)
end
list = db.create_table(:database, :name, :String, :password, :String, :test, :String)
name = 'Test'
password = 'abcde'
list.insert(name, password, nil)
account = list.select { |r| r.name == name}
if account.test.nil?
puts 'right'
else
puts 'wrong'
end
Why does it output "wrong"?
It seems to be strange to answer my own question but I solved the problem: account.test is an array so the correct form of the if statement is:
if account.test[0].nil?
puts 'right'
else
puts 'wrong'
end
Related
Any idea to refactor the code of the method self.import_data ? It's a method which allow the application to save CSV file in database (with some restriction on the user email). It's supposed to run every day at noon so it has to be quick.
Currently its very long to run when I have a big CSV file. I wonder if there a way to make this code more efficient and win some time (or to avoiding the loop or make less request...). I don't really know what makes the process so long actually and how to correct it.
Here is my model :
class Person < ActiveRecord::Base
has_paper_trail
validates :email, uniqueness: true
require 'csv'
def is_former_email?(update_email)
self.versions.each do |version|
next if version.object.nil?
return true if version.object.include?(update_email)
end
end
def self.import_data
filename = File.join Rails.root, '/vendor/people.csv'
CSV.foreach(filename, headers: true, col_sep: ',') do |row|
firstname, lastname, home_phone_number, mobile_phone_number, email, address = row
person = Person.find_or_create_by(firstname: row["firstname"], lastname: row['lastname'], address: row['address'] )
if person.is_former_email?(row['email']) == true
puts "not allowed"
else
person.update_attributes({firstname: row['firstname'], lastname: row['lastname'], home_phone_number: row['home_phone_number'], mobile_phone_number: row['mobile_phone_number'], address: row['address'], email: row['email']})
end
end
end
end
I was a little refactored your code, but for more efficiently I recommend to use gem activerecord-import and optimize versions model for search previous emails.
class Person < ActiveRecord::Base
require 'csv'
FILE_NAME = File.join Rails.root, '/vendor/people.csv'
validates :email, uniqueness: true
has_paper_trail
def self.import_data
people = CSV.new(File.new(FILE_NAME), headers: true, header_converters: :symbol, converters: :all).to_a.map(&:to_hash)
versions_by_item_id = Version.where(item_type: 'Person').select('item_id, object').group_by(&:item_id)
people.each do |person_params|
person = Person.find_or_create_by(person_params.slice(:firstname, :lastname, :address))
if versions_by_item_id[person.id] && versions_by_item_id[person.id].sum { |v| v.object.to_s }.include?(person_params[:email])
puts 'not allowed'
else
person.update_attributes(person_params.slice(:home_phone_number, :mobile_phone_number, :email))
end
end
end
end
I'm trying to write a test to make sure existing users can't register (Using Cucumber, Watir-Webdriver and Page Objects)
I have the following code:
text_field(:email, :id => "user_email")
text_field(:password, :id => "user_password")
text_field(:password_confirmation, :id => "user_password_confirmation")
checkbox(:terms_privacy, :id => "user_accepts_terms")
button(:sign_up_button, :text => "Sign Up")
def unique_username
#username = "qa_automation"+"#{rand(6 ** 6)}"+"#gmail.com"
end
def sign_up
unique_username
self.email = #username
self.password = USERS['PASSWORD']
self.password_confirmation = USERS['PASSWORD']
self.check_terms_privacy
self.sign_up_button
puts "username: #{#username}"
#existing = #username
end
def sign_up_with_existing_account
puts "exisiting username: #{#existing}"
self.email = #exisiting
self.password = USERS['PASSWORD']
self.password_confirmation = USERS['PASSWORD']
self.check_terms_privacy
self.sign_up_button
puts "username: #{#existing}"
end
But the #existing variable is returning nothing. These two lines are giving me back nothing:
puts "exisiting username: #{#existing}"
self.email = #exisiting
So I guess I'm trying to figure out how to pass the #existing variable from the 'sign_up' method to the 'sign_up_with_existing_account' method? Thoughts?
You can't and should not want to do that. Testing would be a tangled mess if running one test could affect the result of another. You should set up the existing user ahead of time (using e.g. Before) so that any test that needs an existing user can take advantage of it.
I am trying to run different code using randomly generated types. Creating random types (self.type) works. However, I want to use these types: Early, Late or On Time to conditionally run code based on the string self.type returns. Thanks in advance!
require 'rubygems'
require 'forgery'
class Forgery::MyRecord< Forgery
TYPES= Forgery::Extend([
{ :type => "Early" },
{ :type => "Late" },
{ :type => "On Time" }
])
def self.type
TYPES.random[:type]
end
a=self.type
puts a
This works up to this line of code. It randomly returns Early, Late or On Time.
But, how can I use type in my method? Thanks!
def self.deadline
if self.type=="Early"
puts "early"
#removed other code
elsif if self.type=="Late"
puts "late"
#removed other code
elsif if self.type=="On Time"
puts "on time"
#removed other code
else
puts "Missing"
end
end
b = Forgery::MyRecord.deadline
puts b
end
end
Your problem is: Every time you call type it returns a random value. Therefore you check against different values in each if condition.
Change your code to this:
def self.deadline
case type
when "Early"
puts "early"
# removed other code
when "Late"
puts "late"
#removed other code
when "On Time"
puts "on time"
#removed other code
else
puts "Missing"
end
end
Using the Ransack gem, I'm trying to sort a simple list on an index page. However, there are both uppercase and lowercase values in the sort field name. To make them sorted useful, the sort should be case insensitive.
This is the model Vendor:
name:string, email:string, address:string, phone:string, fax:string
This is the controller:
class VendorsController < ApplicationController
def index
#search = Vendor.search(params[:q])
#vendors = #search.result
end
And the view:
/index.html.slim
tr
th = sort_link #search, :name, "Name"
th = sort_link #search, :email, "Company Email"
th = sort_link #search, :address, "Address"
Any advice would be greatly appreciated.
What you're looking for is a custom "Ransacker":
class Vendor < ActiveRecord::Base
ransacker :name_case_insensitive, type: :string do
arel_table[:name].lower
end
end
view:
th = sort_link(#q, :name_case_insensitive)
You can solve this for all string columns of a model at once by using this approach:
# lib/ransack_object.rb
module RansackObject
def self.included(base)
base.columns.each do |column|
if column.type == :string
base.ransacker column.name.to_sym, type: :string do
Arel.sql("lower(#{base.table_name}.#{column.name})")
end
end
end
end
end
Then include the ransack object in your model:
class UserWithManyAttributes < ActiveRecord::Base
include RansackObject
end
10 months, maybe too late!!
This solved my problem with posgresql
sort_link #search, 'lowercase(name)', "Name"
Ransack now has a case_insensitive option
you can custom a predicate with case_insensitive: false
Refrences: https://github.com/activerecord-hackery/ransack/wiki/Custom-Predicates
Thanks to hd1 who posted the approach above.
I am posting the actual code here - it's not ideal, since it seems like a wordy workaround.
Still open to cleaner suggestions.
def index
#search = Vendor.search(params[:q])
#vendors = #search.result
if params[:q].present?
params[:q].each do |k, v|
if v == 'name asc'
#vendors = #search.result.sort { |p1, p2| p1.name.downcase <=> p2.name.downcase }
elsif v == 'name desc'
#vendors = #search.result.sort { |p2, p1| p1.name.downcase <=> p2.name.downcase }
end
end
end
end
I have this ruby class with an array of links. As it is now I'm able to save a Paper object even if the array contains links that are not valid urls. I have a method that runs through the array and validates the urls and returns false if a url is invalid. But I want to get an error message when I try to call Paper.save. Is that possible?
class Paper
include MongoMapper::Document
key :links, Array
validates_presence_of :links
def validate_urls
reg = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix
status = []
links.each do |link|
if link.match(reg)
status.push('true')
else
if "http://#{link}".match(reg)
status.push('true')
else
status.push('false')
end
end
end
if status.include?('false')
return false
else
return true
end
end
end
If you're using MongoMapper from GitHub (which supports ActiveModel), see http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
class Paper
include MongoMapper::Document
key :links, Array
validates_presence_of :links
validate :validate_urls
def validate_urls
reg = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix
status = []
links.each do |link|
if link.match(reg)
status.push('true')
else
if "http://#{link}".match(reg)
status.push('true')
else
status.push('false')
end
end
end
if status.include?('false')
# add errors to make the save fail
errors.add :links, 'must all be valid urls'
end
end
end
Not sure if that code works with the 0.8.6 gem but it might.
Also, it doesn't apply in this case but if it weren't an array you could smash it all into a single line:
key :link, String, :format => /your regex here/