Deprecation warning for creating attribute 'currency' - ruby-on-rails

I'm using Rails 3.2.3 with the money-rails gem and I've got a product model which has the following:
My model
class Product < ActiveRecord::Base
attr_accessible :name, :price
composed_of :price,
:class_name => "Money",
:mapping => [%w(price_cents cents), %w(currency currency_as_string)],
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
end
My Test
require 'spec_helper'
describe Product do
context "testing money gem" do
it "creates product with price" do
product = Product.create(:price => 200)
product.price.should eq(200)
product.price_cents.should eq(20000)
end
end
end
Deprecation warning I'm getting.
% rspec spec/models/product_spec.rb
Product
testing money gem
DEPRECATION WARNING: You're trying to create an attribute `currency'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc. (called from block (3 levels) in <top (required)> at /home/map7/project/spec/models/product_spec.rb:6)
creates product with price
Finished in 0.06682 seconds
1 example, 0 failures
How do I fix this deprecation warning?
Update
If I add 'currency' to the table it starts working. Should I have to do this though?

Apparently in Rails 3.2 and above arbitrary attributes (attributes not stored in the database) are no longer allowed. There doesn't seem to be a way around it.
Here is the commit for the deprecation message: https://github.com/rails/rails/commit/b2955edc
and here is why: https://github.com/rails/rails/commit/50d395f96ea05da1e02459688e94bff5872c307b
In your case price_cents and currency still need to be stored in the database and then your composed class will take it from there.

Added 'currency:string' to my model

Related

How to deal with eval nil issues in Rails

I am facing a pretty nasty error in a production environment that caused a bit of confusion. I increased logging on production to narrow down the issue and was now able to reproduce it on our local environment. So setup wises we are running on Rails 5, on a Ubuntu machine. The application uses ElasticSearch 5.4, and we are storing images on Amazon S3.
Process: A user can upload images. There is a User Index in Elasticsearch that also stores information to the related Photo model.
The issue is that once a user uploads a photo, it sometimes comes to an error on an index page or detailed user page where photos are in one way or another accessed. And the results to be displayed are not read from a database but Elasticsearch.
Workaround (which isn't one). Once the index is getting reimported the error doesn't occur any longer - which initially led me to believe that it has something to do with ElasticSearch.
User Model
class User < ApplicationRecord
include UserSearchable
extend FriendlyId
require "redis"
friendly_id :slug_candidates, use: :slugged
has_many :photos
after_update { self.photos.each(&:touch) }
...
end
User Searchable Concern
module UserSearchable
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
index_name Rails.application.class.parent_name.underscore
document_type self.name.downcase
settings index: { number_of_shards: 1 } do
mapping dynamic: false do
indexes :description, analyzer: 'english'
indexes :tagline, analyzer: 'english'
indexes :username
...
end
end
after_touch() { __elasticsearch__.index_document }
def as_indexed_json(_options = {})
self.as_json(
except: [:email, :lat, :lng, :status, :termsofuse, :v_code],
include: {
photos: { only: [:name, :caption, :active, :image_data, :downloadable, :uploader_id, :public] },
).merge(
location: {lat: lat.to_f, lon: lng.to_f},
age: birthday.nil? ? 18 : ((Date.today - birthday.to_date) / 365.25).floor
)
end
def home_search(searcher, order = nil, how_many = nil)
how_many = 400 unless how_many.is_a?(Integer)
order = 1 unless order.is_a?(Integer)
if self.radius < 30
use_radius = 30
else
use_radius = self.radius
end
search_definition = Jbuilder.encode do |json|
json.sort do
if order == 1
json.array! [{'_geo_distance' => { :location => {:lat => lat, :lon => lng} }}, '_score']
else
json.array! ['_score', {'_geo_distance' => { :location => {:lat => lat, :lon => lng} }}]
end
end
json.query do
json.bool do
json.filter do
json.bool do
json.must do
json.array! [:geo_distance => { :distance => use_radius, :unit => "mi", :location => {:lat => self.lat, :lon => self.lng}, :boost => 5.0}]
end
...
unless searcher.id.nil?
json.must_not do
json.array! [ {:term => { 'id' => self.id }} ]
end
end
end
end
...
end
end
# json.size how_many
end
self.class.__elasticsearch__.search(search_definition)
end
end
end
Photo Model
class Photo < ApplicationRecord
include ImageUploader[:image]
include ActiveModel::Validations
acts_as_taggable
before_create :set_name
belongs_to :user, touch: true
after_update { self.user(&:touch) }
private
def set_name
self.name = "Photo"
end
end
Tests of issue in console:
Here, and this is key to the problem. If I eval for the photo sometimes it is nil, and sometimes it is not! And I cannot figure out why? If I run this command lets say 10 times on console, it is nil 2 out of 10 times. And that is when the production system is thrown off its track and the user is presented with an error. As the system is intranet and new we actually show exceptions to users (so do not be alarmed by bad exception handling - users don't say a thing if you don't make it clear ;) )
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
Additional trace:
>> Settings.s3 + eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>>
=> nil
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
>> user.photos.sample.image_data
=> "{\"original\":{\"id\":\"photo/47/image/original-114c9db755b25afe0398f5b25aed5bef.jpg\",\"storage\":\"store\",\"metadata\":{\"size\":61357,\"filename\":\"London-Escort-Angelina (5).jpg\",\"mime_type\":\"image/jpeg\",\"width\":500,\"height\":500}},\"large\":{\"id\":\"photo/47/image/large-c3985d412ee05495594caa659feca371.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":\"shrine-s320170627-29702-17km6c5.jpg\",\"size\":61356,\"mime_type\":\"image/jpeg\",\"width\":500,\"height\":500}},\"small\":{\"id\":\"photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":\"shrine-s320170627-29702-ouo63f.jpg\",\"size\":25642,\"mime_type\":\"image/jpeg\",\"width\":300,\"height\":300}}}"
>> user.photos.sample.image_data[:small]
!! #<TypeError: no implicit conversion of Symbol into Integer>
>> eval(user.photos.sample.image_data)[:small]
=> {:id=>"photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg", :storage=>"store", :metadata=>{:filename=>"shrine-s320170627-29702-ouo63f.jpg", :size=>25642, :mime_type=>"image/jpeg", :width=>300, :height=>300}}
>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>
Any help is much appreciated!!!
Your results are different because you use sample method, whitch choose a random element from user.photos.
For prevent undefined method [] for nil:NilClass error you can use &.dig for ruby >= 2.3 or try if less
nil&.dig(:small, :id)
=> nil
nil.try(:dig, :small, :id)
=> nil
So, I could resolve the issue (workaround-ish) by reindexing the updated user document when a photo is uploaded or deleted. Forgot about the destroy part before. It doesn't seem right as it is messy given an entire record must be removed in ES and reindexed, but traffic is low and for the time being it works. If I figure out the issue, I will revert to this thread.

Stripe Gateway on Active Merchant not working

I was working to make payments through Stripe Gateway through Active Merchant gem on a Rails 4 application.
I came along this script and made a similar script by also watching some other resources as follows:
require 'active_merchant'
# Use the TrustCommerce test servers
ActiveMerchant::Billing::Base.mode = :test
gateway = ActiveMerchant::Billing::StripeGateway.new(:login => Rails.application.secrets.stripe_secret_key)
# ActiveMerchant accepts all amounts as Integer values in cents
amount = 1000 # $10.00
# The card verification value is also known as CVV2, CVC2, or CID
credit_card = ActiveMerchant::Billing::CreditCard.new(
:first_name => 'Bob',
:last_name => 'Bobsen',
:number => '4242424242424242',
:month => '8',
:year => Time.now.year+1,
:verification_value => '000')
purchase_options = {
:ip => "127.0.0.1",
:billing_address => {
:name => "Ryan Bates",
:address1 => "123 Main St.",
:city => "New York",
:state => "NY",
:country => "US",
:zip => "10001"
}
}
# Validating the card automatically detects the card type
if credit_card.validate.empty?
# Capture $10 from the credit card
response = gateway.purchase(amount, credit_card, purchase_options)
if response.success?
puts "Successfully charged $#{sprintf("%.2f", amount / 100)} to the credit card #{credit_card.display_number}"
else
raise StandardError, response.message
end
end
but this script generates an error with the following error log:
/Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:469:in `rescue in api_request': uninitialized constant ActiveMerchant::Billing::StripeGateway::JSON (NameError)
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:463:in `api_request'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:477:in `commit'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:100:in `block (2 levels) in purchase'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:59:in `process'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:98:in `block in purchase'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:45:in `tap'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:45:in `run'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:93:in `purchase'
from stripe.rb:35:in `<main>'
Can you suggest a workaround for this error?
I think you just need to add require 'json'. there's no need to add strip to your gemfile
so it looks like a simple workaround as suggested by #bkunzi01
i thought that active merchant already used stripe in its ActiveMerchant::Billing::StripeGateway file but it doesn't.
just included require 'stripe' at the top of the script and transaction was successful :)

Gibbon::GibbonError at /visitors You must set an api_key prior to making a call

Running OSX Mavericks, ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-darwin13.0], rvm 1.25.23 (master), and rails-4.1.0 (allegedly)
I'm working through the railsapps.org book on learning rails I have finished implementing the mailchimp email list code, and when I press submit on my form, I get the following error:
Gibbon::GibbonError at /visitors
You must set an api_key prior to making a call
I was working through an invalid URI error, and it mysteriously disappeared over the weekend (I haven't touched the Mac since last Friday). Now I have this new error.
My API Key and List ID are valid and properly set. If I look back in the log, I see another error that the mailchimp.lists.subscribe method is missing.
Here's the code as implemented from the book:
class Visitor < ActiveRecord::Base
has_no_table
column :email, :string
validates_presence_of :email
validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
def subscribe
mailchimp = Gibbon::API.new
result = mailchimp.lists.subscribe({
:id => Rails.application.secrets.mailchimp_list_id,
:email => {:email => self.email},
:double_optin => false,
:update_existing => true,
:send_welcome => true
})
Rails.logger.info("Subscribed #{self.email} to MailChimp") if result
end
end
I hate being a noob when I can't debug for myself... Replies are appreciated.
Regards,
Jeff
Gibbon automatically looks for the environment variable MAILCHIMP_API_KEY and Gibbon will use it when you create an instance. If you haven't set a Unix env variable MAILCHIMP_API_KEY, you will need to set it explicitly. To hardcode it:
mailchimp = Gibbon::API.new("your_api_key")
Or obtain it from the config/secrets.yml file:
mailchimp = Gibbon::API.new(Rails.application.secrets.mailchimp_api_key)

shoulda greater and less than syntax

brief.rb
# encoding: utf-8
class Brief < ActiveRecord::Base
belongs_to :project
validate :can_only_be_edited_if_project_is_not_started
validates_presence_of :project, :inverse_of => :brief
validates_numericality_of :duration, :only_integer => true, :less_than_or_equal_to => 15, :greater_than_or_equal_to => 5
validates_length_of :brand_info, :maximum => 4000
def can_only_be_edited_if_project_is_not_started
errors.add(:base, 'Proje can't edit if duration is end!') if
!project.nil? && !project.brief_can_be_edited?
end
end
How can I test duration should greater than or equal to 5 and less than or equal to 15 with shoulda gem?
I tried below code
brief_spec.rb
it { should ensure_inclusion_of(:duration).in_range(5..15)
but I got this error
1) Brief non-specific tests
Failure/Error: it { should ensure_inclusion_of(:duration).in_range(5..15) }
Did not expect errors to include "It's not suitable word" when duration is set to 4, got error:
# ./spec/models/brief_spec.rb:23:in `block (3 levels) in <top (required)>'
This looks to be a known issue right now, with a pull request made to fix this:
https://github.com/thoughtbot/shoulda-matchers/pull/281
I suggest just keeping an eye on this to see if it goes in and check to see when a new gem is created. Once it's in git, you could also pull directly from there without waiting for a new gem. A last alternative would be to fork the gem yourself, add the changes, and use your own gem.
In the mean time, you could use the allow_value matcher if you really needed a test there now.

Feedzirra in Rails 3

I am trying to get feedzirra running on rails 3, I tried by some methods I have found on the internet.
This is in my gemfile:
source 'http://gems.github.com'
gem 'loofah', '1.0.0.beta.1'
group :after_initialize do
gem 'pauldix-feedzirra'
end
And i've out this after bundle.setup in root.rb
Bundler.require :after_initialize
And this is the code in my model (movie.rb)
class Movie < ActiveRecord::Base
def self.import_from_feed
feed = Feedzirra::Feed.fetch_and_parse("url-to.xml")
add_entries(feed.entries)
end
private
def self.add_entries(entries)
entries.each do |entry|
unless exists? :guid => entry.id
create!(
:title => entry.title,
:synopsis => entry.synopsis,
:cover => entry.cover,
:duration => entry.duration,
:channel => entry.channel,
:imdb_rating => entry.imdb_rating,
:imdb_votes => entry.imdb_votes,
:imdb_id => entry.imdb_votes
)
end
end
end
end
I try to run the import_from_feed function from the console and I keep getting this error:
>> Movie.import_from_feed
NameError: uninitialized constant Movie::Feedzirra
from /Users/myname/Ruby/appname/app/models/movie.rb:3:in `import_from_feed'
from (irb):1
Can someone help me out? Been trying for ages now!
Two things:
Just add the gem, not under :after_initialize
Use the feedzirra gem, not the old pauldix-feedzirra one.

Resources