Rails - trying to understand a piece of code - ruby-on-rails

I am working with some code I found online:
def person_path(options)
# This is where the path of the query is constructed.
path = "/people/" # For this section of the LinkedIn API
if id = options.delete(:id)
path += "id=#{id}"
elsif url = options.delete(:url)
path += "url=#{CGI.escape(url)}"
else
path += "~"
end
end
I am not completely certain what it does. what I am trying to do is have it construct a string something like this: http://api.linkedin.com/v1/people/~:(current-status) which I got from the LinkedIn developer docs here: https://developer.linkedin.com/documents/profile-api
Any thoughts on what I should pass this functions and how exactly it accomplishes what it does?
Thanks!

Whilst it's not stated what 'options' is, it's extremely common to pass in options to a method as a Hash of key-value pairs in Ruby, so I'd say that options is just that (with 99% certainty). This is the part that's key to understanding the rest of the code.
I believe that the #delete method on hash is being used in order to pull out the key-value pair and assign the value in one move, whilst taking advantage of the returned object's "truthiness".
http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-delete
And by "truthiness", I mean that in Ruby, all objects evaluate to 'true' except 'nil' and 'false'.
The rest is simple if-else control flow logic that you will have seen in any other language, so I hope this makes sense.

This just creates a path of the form "/people/id=foo" or "/people/url=foo_with_%_escapes" if it finds id or url in the options. As a side effect, it deletes the one it finds from the options. If it doesn't find either one, it gives "/people/~"

Related

Ruby on Rails - using a block parameter as a method call

I'm having trouble with a little Ruby on Rails I'm building and need some help.
I have a Table with 20+ Columns and a corresponding XML File which can be parsed as some sort of hash with a gem. Every key would be mapped to a column and every value would be a data record in said column.
The way I access a specific value in the already parsed XML file is:
filename["crs","inputkeyhere"]
which returns the value, for example "52" or whatever.
What I am trying to do is upload the file, parse it with the gem and give each column the corresponding value.
My table (or model) is called "Attributeset" and I already know how I can access every column:
#attributeset = Attributeset.new
#attributeset.attributes.keys
So my thought process was:
Iterate over all the keys
Pass every key into a block called |a|
Use the rails possibilty to set attributes by calling the corresponding #attributeset.
Set colum attribute to the corresponding xml key
So my code would go something like this:
#attributeset.attributes.keys.each do |a|
#attributeset.a=filename["crs",a]
end
But my problem is, that ruby thinks ".a" is a method and apparently does not evaluate "a" to the block parameter.
I've read through lambdas and procs and whatnot but didn't really understand how they could work for my specific situation.
Coming from bash scripting maybe my thinking might be wrong but I thought that the .a might get evaluated.
I know I can run the block with yield, but this only works in methods as far as I know..
Any help is appreciated.
Thanks and stay healthy,
Alex
Thanks for the input!
I wanted to make it as clean as possible, and not using any temporary hashes to pass arguments.
I've found the method
write_attribute
which can be used like this:
#attributeset.write_attribute(a, xmp["crs",a])
worked perfectly for me.
You can use []= method to set values dynamically:
#attributeset.attribute_names.each do |attribute|
#attributeset[attribute] = filename["crs", attribute]
end

ruby on rails iterating params

I have a client that is sending params such as age, gender, name and so on.
I need to retrieve data from the table based on the params, but first I need to check for the presence of the param(to avoid a null param and therefore an empty result). The params are working as filters, so they can be triggered or they can be left blanck.
What I am doing right now is
#retieve = Student.all
unless params[:age].nil?
#retrieve = #retrieve.where(age: params[:age])
end
unless params[:gender].nil?
#retrieve = #retrieve.where(gender: params[:gender])
end
and so on for every param I receive. This way I check if the filter has been selected, and if it has I use the selection as a parameter for the query
It works, but as Ruby is known for the DRY statement, I am pretty sure someone out there knows a better way for putting this and to make this flexible.
Thank you for whatever answer or suggestion you will provide!
This will work best if all of these filters were in a subhash of params that you can iterate over without including unwanted parameters (eg the :action and :controller parameters that rails adds)
Once you've done that you could do
(params[:filters] || {}).inject(Student.all) do |scope, (key, value)|
scope.where(key => value)
end
There's a few ways to do this sort of thing and you have options for how far you want to go at this stage.
Two big things I'd consider -
1) Make nice scopes that allow you to send a param and ignore it if it's nil. That way you can just append another scope for each param from the form and it will be ignored without using if or unless
2) Move the search into a separate class (a concern) to keep your controller clean.
Here's a blog post that talks about some of the concepts (too much to post in this answer). There is lots of info on the web about this, I searched on the web under "rails search filter params concern" to get an example for you.
http://www.justinweiss.com/blog/2014/02/17/search-and-filter-rails-models-without-bloating-your-controller/

Rails manipulate model query

Assume I have params[:foo] = "bar" and some saved object whose attribute = "key.bar"
How can I manipulate Model.where(attribute: params[:foo]) to query for attribute.split(".")[1] ?
I'm not certain if there's a better way, but the first method that popped in my mind is using the LIKE operator. You can write your query thusly:
Model.where("attribute LIKE '%?'", params[:foo])
Note, given the example you posted, I placed the wildcard (%) in that position so that the attribute is match for anything that ends with your parameter. This assumes all your attributes are similar to what you described, but you can of course change it around to your liking.
Also, while I've never used it myself, I understand that the Squeel gem provides this functionality as an operator (described here).
Small change to answer above
Model.where("attribute LIKE '%.?'", params[:foo])
to prevent matching both .bar and .foobar.

Iterating through array of Models in rails

Yet another ruby question but this is a bunch of questions in one. I'm really starting to like rails but there are some questions that I'd just like to ask straight out.
Right now, I'm implementing a queue in sqlite. I already have a scaffold setup with this working OK. The purpose is for a web crawler to read through the array and determine which links he should crawl next.
The architecture in the program is 2 controllers. one for Job and one for crawler. The Jobs has the standard Crud interface supplied by scaffold. Where I'm falling down is I'm still trying to understand how these things communicate with eachother.
The Job is formatted as a url:string and depth:decimal. The table is already populated with about 4 objects.
#sitesToCrawl = Job.all
#sitesToCrawl.each {|x|puts Job.url}
I have a bunch of questions about the above.
At the moment, this was supposed to display all the jobs and I foolishly thought it would display plain text but its actually a hexidecimal pointer to the object itself. What Im trying to do is iterate through the #sitesToCrawl and put out each Jobs url.
Questions start here:
1: I know ruby is dynamically typed. Will #sitesToCrawl become an array like i want it to be with each slot containing a job.
2: #sitesToCrawl.each is pretty straighforward and I'm assuming its an iterator.
is X the name od the method or what is the purpose of the symbol or string between |*|
3: Puts and print are more or less the same yes? if i say #x = puts 3 then would x be 3?
4: Job.url. Can objects be referenced this way or should I be using
##sitesToCrawl = db.execute("SELECT url FROM jobs;")
where db is a new database
As Rubish Gupta pointed out, in your block, you should do x.url, otherwise you're trying to access the url method on the class Job, not on instances of Job. In other words, in blocks, the items in the pipes are the arguments of the block, and each will iterate through your array, passing in one item at a time to your block. Check out the doc here.
Just to extend this idea, each on Hashes (associative arrays, maps, whatever you know them as) will pass two variables to your block: a key and a value, like this:
a_hash.each {|key_var, val_var| puts "#{key_var} is associated with #{val_var}"}
Also, it's been a bit since I've done plain ActiveRecord models, but you might look into doing
#sitesToCrawl = Job.all.to_a
since Job.all is a lazy finder in that it's building a query in potentia: you've essentially built a query string saying SELECT * FROM jobs, but it might not be executed until you try to access the items. each might do that, I can't remember off the top of my head, but if you're using a debugger to look at it, I know you need to_a to get it to run the query.
You should absolutely be using job_instance.url - that's the beauty of ActiveRecord, it makes database access easy, provided everything gets set up right :)
Finally, puts and print are almost the same - the difference is that puts "string" is essentialy print "sting"; STDOUT.flush - it flushes at the end of the statement.

Accessing object values that have reserved keywords as names in Rails

I'm accessing the Amazon AWS API using the ruby-aaws gem, but without going to much into details of the API or the gem, I think my problem is more of a general nature.
When I query the API I will end up with "object array", let's call it item, containing the API response.
I can easily access the data in the array, e.g. puts item.item_attributes.artist.to_s
Now the API returns attributes whose identifier are reserved words in Rails, e.g. format or binding.
So doing this:
puts item.item_attributes.format.to_s will return method not found
while
puts item.item_attributes.binding.to_s will return some object hash like #<Binding:0xb70478e4>.
I can see that there are values under that name when doing
puts item.item_attributes.to_yaml
Snippet from the resulting yaml show artist and binding:
--- !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::ItemAttributes
__val__:
artist: !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::Artist
__val__: Summerbirds in the Cellar
binding: !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::Binding
__val__: Vinyl
This was probably a very detailed explanation with a very simple solution, but I can't seem to find the solution.
edit
Finally found it. I guess it is because it is an array of objects, duh...
puts item.item_attributes[0].binding.to_s
You may be able to access the individual attributes by using [] instead of the method name (which is probably provided using method_missing anyway).
So, item.item_attributes[:artist].to_s may return what you want. If it doesn't it would be worth trying 'artist' as the key instead.
Finally found it. I guess it is because it is an array of objects, duh...
puts item.item_attributes[0].binding.to_s

Resources