Using Wikipedia-Client Gem to Update Rails Database - ruby-on-rails

My ruby and Rails is a bit rusty. I have a table in my database called institutes which has some of the columns filled. I want to use the Wikipedia-Client gem to fill some of the others. I want to use the name attribute to find the page on Wikipedia then use page.summary for the description attribute in my table and page.image_urls.first for the picture attribute. At the moment, I'm struggling to work out how I would go about this.
My current code is:
require 'Wikipedia'
Institute.each do |institute|
school = institute.pluck(:name)
page = Wikipedia.find(school)
description = page.summary
picture = page.image_urls.first
Institute.update!(description: description, picture: picture)
end
I'm clearly doing something wrong here to do with the selection and use of the name attribute to find the Wikipedia page, but can't quite work it out. I think even if I were to pluck the name correctly, it wouldn't assign anything to the right id.
If there's also a way to drop the "The" at the beginning of the name in the Wikipedia search if it exists in :name, that would also be helpful as it seems some institutes drop this on Wikipedia.

You can try to use something like this:
#use https://github.com/kenpratt/wikipedia-client
require 'wikipedia'
#select all Institutes through AR model
Institute.all.each do |institute|
#'institute' is an object, so we can get its name by dot operator
school = institute.name
#try to find school as is
#then try to find without 'The'
#and go ahead only if page exists
page = Wikipedia.find(school)
page = Wikipedia.find(school[3..-1].strip) if page.content.nil? and school[0..2].downcase == 'the'
next if page.content.nil?
description = page.summary
picture = page.image_urls.first
#update Institute object
institute.update!(description: description, picture: picture)
end

Related

How do I generate all new records for a given model randomly using pre-defined options?

I'd like one of my models, Stones, to be generated at random using pre-defined options I've stored in a set of arrays and hashes. Instead of Create using params from the URL, I'd like new Stones to always be defined using this random generation process. I don't need any user input at all, except that each stone belongs to a given player.
I'm still new to rails; where should I put all this code? I know enough to be able to define the arrays and hashes and randomly select from them when I need to, but I'm not sure where and how to replace the part of the code that draws params from URLs and fills in a new record before it is saved. I know controllers are supposed to be skinny, so do I do this in the model?
Apologies if this is a duplicate. I searched extensively and couldn't find an applicable solution.
Thanks for any help!
I would create a service for this. Something like:
# app/services/stone_creator.rb
class RandomStoneCreator
RANDOM_FOOS = ['bar', 'baz', 'bat']
def self.call(user)
Stone.create!({
foo: RANDOM_FOOS.sample,
user: user
})
end
end
And then anywhere that you need a new random stone you can call it like:
random_stone = RandomStoneCreator.call(current_user)

Rails custom model method in where query

In my rails app I have defined in the Kid model a calculation based on the fields from the Kids DB. the method is as follows:
def flip_date
self.dob.advance(months: 10)
end
I want to use this in my controller as I have a method where I am defining something as follows:
new_kids = Kid.where(discharge_date: nil).where('flip_date > ?', Date.current.advance(year: 1).beginning_of_year)
However I keep getting the following error:
SQLite3::SQLException: no such column: flip_date: SELECT "kids".* FROM "kids" WHERE "kids"."discharge_date" IS NULL AND (flip_date < '2017-01-01')
Any ideas on how can I make this work? All help is appreciated!
If you really want to use model methods take a look at http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select
For your case:
new_kids = Kid.where(discharge_date: nil).select{|k| k.flip_date > Date.current.advance(year: 1).beginning_of_year}
But select method takes every object in memory before returning final result. Hence I will advise to use normal where clause and instead of flip_date take dob (which is a column in database) in consideration.
Like this
new_kids = Kid.where(discharge_date: nil).where('dob > ?', <date criteria>)
The select method (http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select) works great if you are okay with the return being an Array.
I am still looking for a way to do this with an ActiveRecord_Relation return.
If others know how to do this, it would be much appreciated if you can share.
This example doesn't respond to your specific code, but to the extent it helps someone else with a similar question, here's a very simple example of how .select can be really handy:
#expired_memberships = User.select{|u| u.membership_expired_yesterday?}
In that example you've looped through all your Users and filtered them based on a custom method you defined on the User model (membership_expired_yesterday?). Now you can easily do stuff with that collection like this example in a mailer:
#expirations.each do |user|
MembershipExpirationMailer.with(user: user).first_reminder.deliver_now
end

Rails checking if an object is also assigned to another

in my Rails application I've got a n:m relation between movies and tags. (has_and_belongs_to_many)
So each tag can be assign to several movies.
Now when I add new tags to a movie I want to check If this Tag is already assigned to this movie.
What is the esiest way in rails to check if there is a relation ship between the tag and the movie?
I fetch the tag with:
#tagfound = Tag.where("tagname = ?", data[:tagname])
The List with all Tags from the movie can be fetched with this:
#vid.tags
Thanks for your help
You may not need to check. You can simply do this
movie.tags = [array, of, tags]
movie.save # note, you don't need to save. The line above saves.
or
movie.tag_ids = [1,2,3,4]
movie.save # note, you don't need to save. The line above saves.
and that will take care of it setting new tags and removing the ones that are no longer connected. Good for checkbox UI or a tokenizer.
To answer your question, to find if a movie has a tag, you can do this
tag.in?(movie.tags)
And this is the way to add a single
movie.tags << tag unless tag.in?(movie.tags)
[EDIT]
If you do this
movie.update_attributes(movie_params)
and one of the params is the tag_ids, the movie will only save the new tags if it is valid (no other errors).
I believe there are 2 ways you can do this.
Check if #tagfound is included in #vid.tags
#vid.tags.include? #tagfound
Add the tag & call uniq after.
#vid.tags << #tagfound
#vid.tags.uniq!

How to define a Form Override for a Chained Form Field in Active Scaffold

Below example is taken from this documentation page:
https://github.com/activescaffold/active_scaffold/wiki/Chaining-Form-Fields
[Example start]
You can set an array of columns to update multiple columns when a column changes, and chain column updates:
class UsersController < ApplicationController
active_scaffold do |config|
config.columns[:author].form_ui = :select
config.columns[:author].update_columns = [:book, :editorial]
config.columns[:book].form_ui = :select
config.columns[:book].update_columns = :format
end
end
In this example, fields for book, editorial and format are updated when author changes, and when book changes only format is updated. A form override which use the new author or book must be defined for editorial and format columns, in other case those fields won’t change when they will be rendered again.
[Example end]
In the example it states "a form override which use the new author or book must be defined".
Question is how to define those form overrides ??
I have read the documentation on https://github.com/activescaffold/active_scaffold/wiki/Form-Overrides, and tried different form overrides, but with no luck so far, i.e. the columns are not being rendered again.
If you can help me with the code for those form overrides needed in the given example, then I should be able to port that to my code.
Here is the solution to my problem:
I followed the example on "https://github.com/activescaffold/active_scaffold/wiki/Chaining-Form-Fields", but when it did not work for my chained columns (when updating the first column all chained columns updates correctly, but when updating the second column then its chained columns renders to blank lists), then I focused (blindly?) on the details explained just below the example as I thought this was the first step to solve my problem: "A form override which use the new author or book must be defined for editorial and format columns, in other case those fields won’t change when they will be rendered again".
This was however not the case, no form override in the helper was needed to get this to work, in the helper the "options_for_association_conditions" is enough. As the example is for v2.4, maybe the form override is not needed anymore in v3.0+.
The solution is in the next paragraph on the example wiki: "Usually only the value of the changed column is sent, if you need another values to render the updated columns, enable send_form_on_update_column and all the form will be sent". My problem was, that the columns which was chained from the second column needed the value from the first column also, so setting up the second column with "send_form_on_update_column" (i.e. sending the whole form, not just its own value) solved my problem.
In the example this would be:
config.columns[:book].send_form_on_update_column = true

Adding title to rails route

I have List objects which are shown like this:
www.mysite.com/lists/123
Where 123 is the id of the list. What I would like to do is add the title of the list the url so it it more informative(for google or whatever). So I would like it to look like:
www.mysite.com/lists/123/title-of-list-number-123
How do you go about adding to a url like this? If you just enter:
www.mysite.com/lists/123 w/o the title, should it find the title and then redirect to a new route?
If you want to keep your find-calls as they are (by id), you could do the opposite of what mplacona suggested:
def to_param
"#{id}-#{title.parameterize}"
end
With this, your find(params[:id]) will work because it'll convert the string to an integer (can only succeed if the number is in the beginning of the string). So this is will actually work:
List.find("123-my-title")
and will be the same as
List.find(123)
Read more about this and other ways to accomplish this here: http://gregmoreno.ca/how-to-create-google-friendly-urls-in-rails/
The parameterize will automatically convert the string to a "pretty" url. Read more here: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html#M001367
If you want a bit more functionality, I'll suggest friendly_id aswell.
This article says exactly what you need to do accomplish this.
http://railscasts.com/episodes/63-model-name-in-url
UPDATE
Have a permalink added to your model, and save as follow to it:
def to_param
"#{permalink}-#{id}"
end
On your controller, instead of getting things by the id, get them by the pemalink:
#product = Product.find_by_permalink(params[:id])
And that's all you need.
The screen cast explains all the steps on how to do it.
You could also take a look at friendly id, if you're in the mood for a gem/plugin.

Resources