I am trying to check if the domain host url record exist in the domain table before creating it again, but I am getting this error:
undefined method `new_record?' for #<Domain::ActiveRecord_Relation:0x007f320ed8af80>
The class GetMeta is a service object that is getting initialize when a user enter a URL in a form and click submit. I am taking the URL from the form and calling MetaInspector with it to get more meta informations.
The first part (if) new_record method is working perfectly fine, but is creating duplicate values in the domain table. I tried to create a conditional logic, but I am having this bug that I don't know how to fixed.
class GetMeta
include ActiveModel::Model
def initialize(url)
#url = url
end
def new_record
page = MetaInspector.new(#url)
#domain = Domain.where(:host => page.host)
if new_record?
Domain.create! do |url|
url.root_url = page.root_url
url.scheme = page.scheme
url.host = page.host
url.links.build(url: page.url, title: page.best_title, description: page.description)
end
else
Link.create! do |link|
link.url = page.url
link.title = page.best_title
link.description = page.description
end
end
end
private
def new_record?
#domain.new_record?
end
end
The problem is described by an error. Let's see:
undefined method `new_record?' for
#<Domain::ActiveRecord_Relation:0x007f320ed8af80>
The problem is the line
#domain = Domain.where(:host => page.host)
This returns an ActiveRecord relation instead of single record.
You should take a .first or .last.
#domain = Domain.where(:host => page.host).last
That's the fix, but let's see how can we improve the code.
We can use method exists? which is defined in ActiveRecord Relation (docs: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F)
if Domain.exists?(host: page.host)
Link.create! do |link|
link.url = page.url
link.title = page.best_title
link.description = page.description
end
else
Domain.create! do |url|
url.root_url = page.root_url
url.scheme = page.scheme
url.host = page.host
url.links.build(url: page.url, title: page.best_title, description: page.description)
end
end
This way we don't need instance variable #domain and helper method new_record?
You are calling an instance method from within an instance method. So you need to specify which instance you are referring to. You need to use 'self'. So instead of just calling 'new_record?', try calling self.new_record?
Related
I want to retrieve all the tweets that have a certain hashtag in them.
At first I add the hashtags in my 2 tables :
def add_hashtags(tweet)
tweet.content.scan(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/){ |tag|
#allhashes = Hashtag.all
#hash = Hashtag.find_by_name(tag[0].strip)
unless #hash
#hashtag = Hashtag.new(name: tag[0].strip)
#hashtag.save
#hashrel = Hashrelation.new(tweet_id: tweet.id, hashtag_id: #hashtag.id)
#hashrel.save
else
#hashrel = Hashrelation.new(tweet_id: tweet.id, hashtag_id: #hash.id)
#hashrel.save
end
}
end
then I want to route to the show method of tweet controller :
get 'tweets/show/(.:format)' => 'tweets#show', as: :hashtag
The links in the hashtags are as follows:
def twitify(tweet = '')
tweet.gsub(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/) do |tag|
" " + link_to("#{tag.strip}", hashtag_path(tag.strip), {:name => tag.strip})
end.html_safe
end
And finally the show method of the tweet controller is :
def show
#hashtag = Hashtag.find_by_name(params[:name])
#tweet_ids = Hashrelation.find_by_hashtag_id(#hashtag.id)
#feed_items = Tweet.find_by_id(#tweets_ids.id)
end
When I click on the link I get :
undefined method `id' for nil:NilClass
which means that params[:name] is either nill or it isn't like the one I have in the DB.
Could you guys help me figure this out ?
The link I see that is called is 'http://localhost:3000/tweets/show/.%23dadawea' which means I have extra things why would I ?.
I would do the following
def add_hashtags(tweet)
tweet.content.scan(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/).flatten.each do |tag|
hashtag = Hashtag.where(name: tag.strip).first_or_create
Hashrelation.create(tweet_id: tweet.id, hashtag_id: hashtag.id)
end
end
Then change the twitify method to look like
def twitify(tweet = '')
tweet.gsub(/(?:\s|^)(?:#(?!(?:\d+|\w+?_|_\w+?)(?:\s|$)))(\w+)(?=\s|$)/) do |tag|
" " + link_to("#{tag.strip}", hashtag_path(name: tag.strip))
end.html_safe
end
And the show method
def show
#hashtag = Hashtag.find_by_name(params[:name])
#tweet_ids = Hashrelation.where(hashtag_id: #hashtag.id).pluck(:id)
#feed_items = Tweet.where(tweet_id: #tweets_ids)
end
This should be what you are looking for. Now for whats changing:
Removed Duplicate logic in the add_hashtags to use create instead.
twitify method is passing name as an html option not a url option so I fixed that. Right now it thinks you want to set the format to the name of the hashtag and name the link the name of the hashtag**
show method is using find_by which will only return a single result not what you wnat for tweet_ids so i changed it to where clause and just grabbed the ids. Then changes feed_items to search Tweet for all tweet_ids in the Array.
To strip the # just use tag.strip[1..-1]
Need a little help over here :-)
I'm trying to extend the Order class using a decorator, but I get an error back, even when I use the exactly same code from source. For example:
order_decorator.rb (the method is exactly like the source, I'm just using a decorator)
Spree::Order.class_eval do
def update_from_params(params, permitted_params, request_env = {})
success = false
#updating_params = params
run_callbacks :updating_from_params do
attributes = #updating_params[:order] ? #updating_params[:order].permit(permitted_params).delete_if { |k,v| v.nil? } : {}
# Set existing card after setting permitted parameters because
# rails would slice parameters containg ruby objects, apparently
existing_card_id = #updating_params[:order] ? #updating_params[:order][:existing_card] : nil
if existing_card_id.present?
credit_card = CreditCard.find existing_card_id
if credit_card.user_id != self.user_id || credit_card.user_id.blank?
raise Core::GatewayError.new Spree.t(:invalid_credit_card)
end
credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
attributes[:payments_attributes].first[:source] = credit_card
attributes[:payments_attributes].first[:payment_method_id] = credit_card.payment_method_id
attributes[:payments_attributes].first.delete :source_attributes
end
if attributes[:payments_attributes]
attributes[:payments_attributes].first[:request_env] = request_env
end
success = self.update_attributes(attributes)
set_shipments_cost if self.shipments.any?
end
#updating_params = nil
success
end
end
When I run this code, spree never finds #updating_params[:order][:existing_card], even when I select an existing card. Because of that, I can never complete the transaction using a pre-existent card and bogus gateway(gives me empty blanks errors instead).
I tried to bind the method in order_decorator.rb using pry and noticed that the [:existing_card] is actuality at #updating_params' level and not at #updating_params[:order]'s level.
When I delete the decorator, the original code just works fine.
Could somebody explain to me what is wrong with my code?
Thanks,
The method you want to redefine is not really the method of the Order class. It is the method that are mixed by Checkout module within the Order class.
You can see it here: https://github.com/spree/spree/blob/master/core/app/models/spree/order/checkout.rb
Try to do what you want this way:
Create file app/models/spree/order/checkout.rb with code
Spree::Order::Checkout.class_eval do
def self.included(klass)
super
klass.class_eval do
def update_from_params(params, permitted_params, request_env = {})
...
...
...
end
end
end
end
I am trying to download products from a Magento store into my Rails database using the "magento-rb" library located here: https://github.com/joelvh/magento-rb
I've tried the following code:
xml_api = Magento::XmlApi.new "http://website.com/api/xmlrpc/", "myusername", "mypassword", :debug => true
products = xml_api.call("catalog_product.list")
products.each do |p|
#exists = Product.where("sku = ?",p["sku"])
if #exists
#product = Product.find_by_sku(p["sku"])
else
#product = Product.new
end
#product.sku = p["sku"]
#product.name = p["name"]
#product.mage_product_id = p["product_id"]
#product.save
end
Unfortunately I am getting this error:
NoMethodError in Admin::ProductsController#test
undefined method `sku=' for nil:NilClass
I should note that I have confirmed that "sku" is indeed an attribute to the Product model, and I have also tried resetting the server. Any ideas?
The way you wrote the code, #exists is always true so even when the sku doesn't exist, the where() method will return an empty array which evaluates to true in ruby.
The only values that evaluate to false in ruby are false and nil.
That's why when you use Product.find_by_sku, it returns nil because the sku doesn't exist and THAT is why you're getting the error undefined method sku= for nil:NilClass.
It's like you're writing nil.sku = p['sku'] which won't work.
To check the existence of a record in the database, it's better to use the 'exists?' method:
if Product.exists?(["sku = ?",p["sku"]])
# product exists
else
# product doesn't exist
end
You can actually skip the extra record checking and only use the find_by_sku method to both check for existence and get the record if it exists at the same time. The following code does the same thing, but it's more "ruby-like":
#product = Product.find_by_sku(p['sku'])
#product = Product.new unless #product
#product.sku = p['sku'] # this is unnecessary
#product.name = p['name']
#product.mage_product_id = p['product_id']
#product.save
Given the following associations:
User has_many Ultimate_Source
User has_many Budget_Source
How do I create the following method:
def foo(source)
user = User.find(1)
user.source.id
end
such that
foo(ultimate_sources)
returns:
user.ultimate_sources.id
thanks.
if source == :ultimate_sources or source == :budget_sources then the following should work.
user.send(source).id
if source is a string you can always convert it to a symbol using source.to_sym.
The send method takes a symbol representing the name of a method and sends the message to that object to execute that method and return what the method returns.
http://ruby-doc.org/core-2.1.2/Object.html#method-i-send
You can use the method .send:
def foo(source)
user = User.find(1)
user.send(source.to_s).id
end
Or the method .try (will not raise a NoMethodError if source is not a method of User):
def foo(source)
user = User.find(1)
user.try(source.to_s).id
end
But I really hope that source is not something coming from the user's input. What if I send delete as value of source variable? It would delete the user ...
I highly recommend you to limit the possible methods, in your case it could be something like this:
def foo(source)
user = User.find(1)
user.try("#{source.gsub('_sources', '')}_sources").try(:id)
end
This code version protects you to send destroy as the source value:
foo('ultimate_sources') # => user.ultimate_sources.id
foo('destroy') # => nil
foo('destroy_sources') # => nil
foo('budget') # => user.budget_sources.id
You could also put in a guard clause to be safe.
def foo(source)
return if (source != 'ultimate_sources') || (source != 'budget_sources')
user = User.find(1)
user.send(source).id
end
In our customer model (rails 3.2.12), a method find_customers is defined as follows:
def find_customers
customers = Customerx::Customer.scoped
customers = customers.where("sales_id = ?", sales_id_s) if sales_id_s.present?
customers
end
The sales_id_s is passed in via params[:customer][:sales_id_s] through a view form. We want to use the same find_customers method to return customers in customers controller index action. The code is:
def index
if has_index_individual_right?('customerx_customers')
params[:customer][:sales_id_s] = session[:user_id]
customer = Customerx::Customer.new(params[:customer])
#customers = customer.find_customers
else
......
end
......
end
However the code params[:customer][:sales_id_s] = session[:user_id] causes the error: undefined method[]=' for nil:NilClass`. In debug, params[:customer] returns nil.
Is there a way to create params[:customer] object in index action so we can call the model method find_customers?
Thanks for the help.
You can ensure it exists (and is a Hash) by using this params[:customer] ||= {}