Override gem method in rails - ruby-on-rails

I want to let users add interests -TV shows in this case-, and to make sure they type a correct tv show, I'm going to search imdb first and let them select one of the returning titles.
I found this gem https://github.com/ariejan/imdb which is doing almost what I need. If I search for "The vampire diaries", it will return it and 200 extra matches.
I went through the gem and I found that he does the querying part here https://github.com/ariejan/imdb/blob/master/lib/imdb/search.rb.
def self.query(query)
open("http://akas.imdb.com/find?q=#{CGI.escape(query)};s=tt")
end
That query basically uses this link http://akas.imdb.com/find?q= and returns everything that can find given the input - movies, tv shows, episodes. Now I found a more advanced query which uses type and some other params. So I could actually return only 4 results in that case instead of 250. All I have to do is to replace that query with http://www.imdb.com/search/title?title=The%20Vampire%20Diaries&title_type=tv_series.
How do I override that search method?

You can re-open the class to override the method:
class Imdb::Search
def self.query(query)
# your custom logic here
end
end
Note that you can call super(query) in your version to get the result of the original.

You can use class_eval and put it in a decorators folder
app/decorators/imdb/search_decorator.rb
class Imdb::Search.class_eval do
def self.query(query)
end
end

Related

How can I set virtual attributes in the mongoid search gem

I am having a hard time with the mongoid_search gem on a few fronts and I wonder if it is working properly. As per the instructions, I am trying to create virtual attributes so that I can search on custom keywords that I create. Here are the instructions from the web page.
You can also search in "virtual" fields by defining them as methods. This can be useful when you have a method with dynamic fields (i.e. variable schema)
class ModelWithDynamicFields
...
search_in :search_data
def search_data
# concatenate all String fields' values
self.attributes.select{|k,v| v.is_a?(String) }.values.join(' ')
end
end
Mongoid_search will run the method before save and use it's output to populate the _keywords field.
I've found that this is not the case and Im trying to find outif I am doing something wrong or if there may be a problem with the gem.
Here is my code.
class User
search_in :search_data
def search_data
["#{self.attributes["email_address"]}", "#{self.attributes["first_name"]}", "#{self.attributes["last_name"]}"]
end
What I want the output to be in the _keywords array is the output of my virtual search_data method which should be this
[allanj#gmail.com allan jones]
This should be the EXACT keywords array that I want yet, the gem keeps ignoring the output of this code and goes to the default behavior. Is there something I can do to fix this?

Ruby error - Undefined Method

I am try to write a function that will find the items in an array which match the string passed to the function. See code below.
class Island
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}</i>
How i keep getting "undefined method 'filer' for #
I'm not sure what i'm doing wrong.
First let me object against the solution posted by #Sravan :
While it is true - and sometimes even a good solution - to monkey-patch a class, you have to be careful how to do it, because it may become a time bomb:
Ruby evolves, and new versions often add methods to existing classes. This means that if you add a method Array#search, and a new version of Ruby will also add a method of the same name, your new method will SILENTLY override the one in Ruby. You likely won't notice it for long time, until you are using a feature which is supposed to use Rubys Array#search - maybe by using something new in stdlib - and you get weird results. To track down this type of error can be a nightmare. This is exactly the case when you use search as a method name.
Now, how to do it then? Three possibilities:
(1) If you monkey-patch, use at least a method name which is unlikely to become part of the official interface. It might have your project's name as a prefix, or plenty of underscore characters, and so on. Note that this is not 100% foolproof: A later version of Ruby might add under the hood a private method with exactly the same name than the one you were choosing, but of course the odder your name, the less likely this will happen.
(2) If you don't like this idea of using "clumsy" names, you could at least test before defining the new method, whether it already exists, and throw an exception if it doesn't:
class Array
if self.method_defined?(:search)
raise "#{self.class}::search already defined"
else
def search(...)
...
end
end
end
(3) The third possibility is to avoid monkey-patching and keep the method in your Island class. In this case, the method definition would be different:
class Island
def self.filter(array, string)
...
end
end
and it would be called by
Island.filter(myarray, mystring)
UPDATE: Forgot a forth possibility:
(4) You can make Island a subclass of Array. I don't know what else you want to do with your islands, but maybe this is an option worth considering:
class Island < Array
def filter(string)
...
end
end
Of course, when invoking filter, you need to turn your array into an island, before you can use it:
list = Island.new([....])
Following ruby's convention over configuration, you can add/overwrite any method in any class
So, adding a function to array class makes it accessible to all the arrays. So, in this solution.
1) First thing is you have taken the filter function in Island class, instead, you need to take inside Array class since the list is an array.
class Array
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}
O/P:
anthony
andre
antoinette
2) Since Filter is a keyword as suggested by other answer, take another name for it. Eg: search
class Array
def search(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list.search("an"){|i| puts i}

rails modle base search with check boxes

I am working on search functionality in rails and I want a common search method for all the site. For that I am creating a method in app controller with two parameters one is modleName and another one is fieldsArray. but am not able to make it. Please help me.
I want that I set a variable in model that on which columns I need a search as like (attr_accessible) and then I need a element which I call in view files and it gets all the columns with labels and check boxes which I set in model. and I get a result with the specific column name which I enter in search box and which columns I have selected, columns would be multiple selected.
Please help.
Thanks
Hope this helps:
Create a utility class which has your generic search method.
class Util
# modelName is a string, fields would be an array of strings, keyword is string as well
# You could either call fire search from here or from individual models
def search(modelName, fields, keyword)
query = ""
fields.size.each_with_index do |field, index|
query += "#{field} like #{keyword} "
query += " OR " if index < fields.size
end
modelName.constantize.where(query)
# Or create search method in all ur models which you want to search and
modelName.constantize.search(fields, keyword)
end
end
I haven't included the model search methods as its self explanatory as to what the method should look like.
Let me know if this helps

Simple recursive method

I have Board model. Board can be subscribed to other boards (as a feed).
Lets say I have board tree like this:
http://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Binary_tree.svg/200px-Binary_tree.svg.png
So:
Board.find(2).feeds are boards 5 and 7
Board.find(7).feeds are boards 2 and 6 etc.
I want to write method all_feeds which returns all feeds from all levels for certain board. For example:
Board.find(7).all_feeds would output array of boards with ids: 2,6,5,11
I started with something like:
def all_feeds
if feeds.empty?
return
else
feeds.each {|feed| feed.all_feeds}
return feeds
end
end
Probably have to add this return feeds to some global array, but not sure how should I do this.
Thanks for help.
ps. this is not always a binary tree, you can have more than 2 feeds.
I guess that what you want could be achieved with:
def all_feeds
unless feeds.empty?
feeds + feeds.map(&:all_feeds).flatten.compact
end
end
Array#flatten makes the result one-dimensional, while Array#compact removes the nil components.
For an explanation of the map(&:all_feeds) part, you can refer to this SO answer :)
Looks like it's working for below code:
def all_feeds
if feeds.empty?
self
else
[self]+feeds.map(&:all_feeds)
end
end
if it is allowed to use gems ancestry gem will help do the trick
Board.find(7).descendants
in this case it will be definitely one request to db without any recursion which is better for performance
you can implement ancestry idea without gem (or in top of it):
add ancestry field to your model
fill it correctly when you build your tree (for nested nodes with ids 2 and 6 it will be 2/7, with ids 5 and 11 - 2/7/6 )
and then just take it from db with like 2/% query

Can I access the collection an instance method was called on in ruby on rails

I'm working on implementing a search form in a ruby on rails application. The general idea is to use form_tag to submit the search fields (via params) to a search function in the model of the class I'm trying to search. The search function will then iterate through each of the params and execute a scoping function if the name of the function appears in params.
The issue is that when I call the search on a collection like so:
#calendar.reservations.search({:search_email => "test"})
I don't know how to refer to the collection of #calendar.reservations from within the search function.
Additionally I'm confused as to why #calendar.reservations.search(...) works, but Reservations.all.search gives me an error saying you can't call an instance method on an array.
I've got the details of the search method over here: https://gist.github.com/783964
Any help would be greatly appreciated!
I don't know how to refer to the
collection of #calendar.reservations
from within the search function.
If you use self (or Reservation, it's the same object) inside the classmethod, you will access the records with the current scope, so in your case you will see only the reservations of a particular calendar.
[edit] I looked at you search function, and I think what you want is:
def self.search(search_fields)
search_fields.inject(self) do |scope, (key, value)|
scope.send(key, value)
end
end
Additionally I'm confused as to why
#calendar.reservations.search(...)
works, but Reservations.all.search
gives me an error saying you can't
call an instance method on an array.
#calendar.reservations does not return a standard array but a (lazy) AssociationCollection, where you can still apply scopes (and classmethods as your filter). On the other hand Reservation.all returns a plain array, so you cannot execute search there (or any scope, for that matter).
You don't really need a search method at all, as far as I can tell.
Simply use where:
#calendar.reservations.where(:search_email => 'test')
I would strongly encourage you to look at the MetaSearch GEM by Ernie Miller. It handles the kind of thing you're working on very elegantly and is quite easy to implement. I suspect that your view code would almost accomplish what the GEM needs already, and this would take care of all your model searching needs very nicely.
Take a look and see if it will solve your problem. Good luck!
Reservation.all.search doesn't work because it returns all the results as an array, while Reservation.where(..) returns an ActiveRecord object (AREL). Reservation.all actually fetches the results instead of just building the query further, which methods like where, limit etc do.

Resources