Create empty object and set its attribute to something - ruby

I have an action in my controller called update_models where I set an instance variable called #selected_model based on the value of params[:model_id]:
def update_models
if params[:model_id].blank?
// create object with id attribute equals '0'.
else
#selected_model = Model.find(params[:model_id]
end
end
In the first part of the if statement, how can I assign #selected_model an empty object and set its id attribute to '0', so that I can access that attribute in my view using #selected_model.id?

Assuming that params is not nil
def update_models
#selected_model = Model.find_by_id( params[:model_id] ) || Model.new( id: 0 )
end

Can't you do this?
def update_models
if params[:model_id].blank?
#selected_model = Model.new
#selected_model.id = 0
else
#selected_model = Model.find(params[:model_id]
end
end

Maybe you can try something like (with no if condition):
def update_models
#selected_model = Model.find(params[:model_id])
rescue
#selected_model = Model.new
#selected_model.id = 0
end

Related

Changing argument inside a function using yield

I am new to the concept of yield and currently practising it.
I was expecting to get ["bread", "JUICY", "bread"]
but I got ["bread", "steak", "bread"].
Can you please help me understand why? And how can I fix my code?
def burger(patty)
if block_given?
yield(patty)
end
return ["bread", patty, "bread"]
end
# TODO: Change 'steak'to 'JUICY'using yield
juicy_burger = burger("steak") do |patty|
patty = "JUICY"
end
p juicy_burger
juicy_burger = burger("steak") do |patty|
patty = "JUICY"
end
Reassignments like this are not propagated to the outer scopes. Once this block returns, patty "reverts" to its initial value.
Solution? Use the overwritten value while it's still in scope.
def burger(patty)
if block_given?
patty = yield(patty)
# ^ shadow the parameter here.
# doesn't have to be a shadow. You can use any name. new_patty = yield(patty)
end
return ["bread", patty, "bread"]
end
juicy_burger = burger("steak") do |patty|
"JUICY #{patty}" # <- simple return here
end
p juicy_burger # >> ["bread", "JUICY steak", "bread"]
The variable is local to the function and you did not save back the value yield returned. The code below will give you ["bread", "JUICY", "bread"]
def burger(patty)
if block_given?
patty = yield(patty) # <-- this is the diff
end
return ["bread", patty, "bread"]
end
# TODO: Change 'steak'to 'JUICY'using yield
juicy_burger = burger("steak") do |patty|
patty = "JUICY"
end
p juicy_burger

ShadowingOuterLocalVariable rubocop error

here is my code, and here is my error. I think dont need to more descriptions here:
#terminal-error (error on object "= ->(object) do "
lib/form_object/base.rb:18:30: W: Lint/ShadowingOuterLocalVariable: Shadowing outer local variable - object.
need_validation = ->(object) do
def valid?
valid_attributes = []
attributes.each do |attribute_name, _attributes|
attribute_set = self.class.attribute_set[attribute_name]
object = self[attribute_name]
need_validation = ->(object) do
(object.class < FormObject::Base || attribute_set.options[:validate]) && object.respond_to?(:valid?)
end
if need_validation.call(object)
valid_attributes << object.valid?
elsif object.is_a?(Array)
object.each do |nested|
valid_attributes << nested.valid? if need_validation.call(nested)
end
end
end
valid_attributes << super
valid_attributes.all?
end
It's a warning from a lint that you run, which detects cases where you shadow (i.e. hide) another local variable, from an outer scope.
You have:
object = self[attribute_name]
need_validation = ->(object) do
(object.class < FormObject::Base || attribute_set.options[:validate]) && object.respond_to?(:valid?)
end
So the first variable object could not be referred to inside the lambda, as the argument is also called object.
You can remove this warning by simply renaming the parameter of your lambda:
need_validation = ->(obj) do
(obj.class < FormObject::Base || attribute_set.options[:validate]) && obj.respond_to?(:valid?)
end

Using variable declared in one method to open webpage in another method

I am working on a CLI Project and trying to open up a web page by using url variable declared in another method.
def self.open_deal_page(input)
index = input.to_i - 1
#deals = PopularDeals::NewDeals.new_deals
#deals.each do |info|
d = info[index]
#product_url = "#{d.url}"
end
#product_url.to_s
puts "They got me!"
end
def self.deal_page(product_url)
#self.open_deal_page(input)
deal = {}
html = Nokogiri::HTML(open(#product_url))
doc = Nokogiri::HTML(html)
deal[:name] = doc.css(".dealTitle h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
deal[:purchase] = doc.css("div a.button").attribute("href")
deal
#binding.pry
end
but I am receiving this error.
`open': no implicit conversion of nil into String (TypeError)
any possible solution? Thank you so much in advance.
Try returning your #product_url within your open_deal_page method, because now you're returning puts "They got me!", and also note that your product_url is being created inside your each block, so, it won't be accessible then, try creating it before as an empty string and then you can return it.
def open_deal_page(input)
...
# Create the variable
product_url = ''
# Assign it the value
deals.each do |info|
product_url = "#{info[index].url}"
end
# And return it
product_url
end
In your deal_page method tell to Nokogiri to open the product_url that you're passing as argument.
def deal_page(product_url)
...
html = Nokogiri::HTML(open(product_url))
...
end

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

How to return a particular value from a method?

I have this code that tries to return a value from a method:
temp = "123"
return temp
and I have this line that calls the method and assigns the return value:
person_connections = #client.get_person_connections(:id => current_user_id )
but when I try to inspect person_connections, it shows some different object string. Any idea how to return the actual value of the temp variable?
def get_person_connections(options = {})
person_id = options[:id]
path = "/people/id=" + person_id + ":(num-connections)"
query_connections(path, options)
self
end
and
private
def query_connections(path, options={})
fields = options.delete(:fields) || LinkedIn.default_profile_fields
if options.delete(:public)
path +=":public"
elsif fields
path +=":(#{fields.map{ |f| f.to_s.gsub("_","-") }.join(',')})"
end
headers = options.delete(:headers) || {}
params = options.map { |k,v| v.is_a?(Array) ? v.map{|i| "#{k}=#{i}"}.join("&") : "#{k}=#{v}" }.join("&")
path += "?#{params}" if not params.empty?
temp_var = get(path, headers)
hash = JSON.parse(temp_var)
conn = hash["numConnections"]
end
As Samy said in a comment:
In Ruby, the last statement will be returned.
So if we take a look at get_person_connections, we see that the last line is self. What it means is that it returns the instance on which the method was called, #client in this case.
Additional notes: the solution would be to remove self, although if the method is used elsewhere be careful as returning self is often used to allow chaining of methods (though it hardly makes sense to do that on a get method).

Resources