Can I ignore certain fields that are too long in Hirb? - ruby-on-rails

I am using Hirb in my Rails console to try to display mongoid records in a nicer looking table, but the _id, created_at, and updated_at fields take too much space and, even though I really have one meaning field, name, when I do a Project.first it returns a rather disintegrated table:
Is there any chance that there's a way to 'ignore' or 'hide' certain fields?

When you open up hirb, run this:
table projects, :fields => [:name]
Then Project.all and enjoy! ;-)
Also see this: Hirb - Irb On The Good Stuff.
UPDATE:
"Hirb also supports a yaml configuration file (config/hirb.yml or ~/.hirb.yml)"
---
:output:
Project:
:options:
:fields:
- name

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?

How can I match a partial string to a database's object's attribute? Regexp?

I have a database containing a list of movies. A typical entry look like this:
id: 1,
title: "Manhatten and the Murderer",
year: 1928,
synopsis: 'some text...'
rating: 67,
genre_id, etc. etc.
Now I'm trying to make a series of search tests pass and so far I have made a single test case pass where if you type the title "Manhatten and the Murderer" in a text field it will find the movie that you want. The problem is with partial matching.
Now I'd like a way to search "Manhat" and match the record "Manhatten and the Murderer". I also want it to match with any movie that has "Manhat" in it. For example, it would return maybe 2 or 3 others like title: "My life in Manhattan", title: "The Big Apple in Manhattan" etc. etc.
Below is the code that I have so far in my Movie model:
def self.search(query)
# Replace this with the appropriate ActiveRecord calls...
if query =~ where(title:)
#where(title: query)
binding.pry
end
end
My question is, how can I set this up? My problem is the "where(title:) line. One thought was to use Regexp to match the title attribute. Any help would be appreciated! Thanks.
Use a query that searches a substring in between:
name = "Manhattan"
Movie.where("title like ?", "%#{name}%")
For example:
%Manhattan will get you: Love in Manhattan
Manhattan% will get: Manhattan and Company
%Manhattan% will get you both: [Love in Manhattan, Manhattan and Company]
But, if you're searching through movies synopsis, you should use Thinking Sphinx or Elastic Search
For example, with Elastic Search, you could set the synopsis like this:
Add app/indices/movie_index.rb:
ThinkingSphinx::Index.define :movie, :with => :active_record do
# fields
indexes title, :sortable => true
indexes synopsis
end
Index your data with rake ts:index
And then run Sphynx with: rake ts:start
You can search just like this:
Movie.search :conditions => {:synopsis => "Manhattan"}
Elastic Search is a great alternative to ThinkingSphinx, there's even a RailsCast about it, so you should definitely take a look to see what really suites you best... Hope this helps!
You do not need regex to find movies that have the search string. You can use SQL query like this:
Movie.where('title LIKE ?','Batman%')
That would return all movies start with "Batman"
Movie.where('title LIKE ?','%Batman%')
That would return all movies that have Batman anywhere in it's title.
I think you figured out the '%' is a joker character in the query.
One option is to run a search server alongside your Rails application. It is certainly my go to solution. This route offers a ton of features not found within Rails itself and might be overkill, but worth consideration.
I use Sphinx and implement it using the thinking-sphinx gem.
Resources:
http://pat.github.io/thinking-sphinx/
http://sphinxsearch.com/

How to find and replace data in a column via Rails migration

I have a column called "meta" in a table called "Notifications". The data in the column looks something like this:
---
:full_name: Dude
:user_id: 1
:update_id: 10
:update_type: want
:update_name: Some name here
and I want it to be changed to something like this:
---
:full_name: Dude
:user_id: 1
:post_id: 10
:post_type: want
:post_name: Some name here
What would a migration to achieve this look like?
def up
execute "update notifications set meta = replace(meta, 'update', 'post')"
end
I'm not entirely sure about the double quotes / single quotes, as I've seen both sometimes working sometimes failing even within different versions of the same SQL engine.
It is usually a good idea to use SQL to migrate data, as your ruby models might change over time and render your migration unusable, e.g. due to altered validation constraints. The same in ruby would look like
def up
Notification.find_each{ | n | n.update_attribute(:meta, n.meta.gsub('update','post')) }
end

Find the list of list of indexed keys in mongomapper

I am working on a rails app with mongodb and mongomapper. I would like to index few keys in the database. This is first project for me on mongo.
The keys i want to index i can specify like this
User.ensure_index(:email)
as described here
My question is, do i need to call this manually(may be wrapping it in a method) to make the indexing really happening?
And how can i find the list of keys which are having indices?
Here are the answers to my questions
Do i need to call this manually(may be wrapping it in a method) to make the indexing really happening?
Yes, we have to manually call the ensure_index method on Model. So we can wrap that in a method and can call from the console or even a rake task.
def self.create_index
self.ensure_index(:email)
self.ensure_index(:first_name)
self.ensure_index(:last_name)
true
end
then from console
User.create_index
you can check what keys are indexed using mongo's getIndexes() method
like this
mongo #=> enter the mongo console
show dbs #=> see the list of available dbs
use my_database #=> switch to your database
db.table_name.getIndexes() #=> replace table_name with your's
and that's it, you can see the list of indices on your table
Thanks!

Postgres accent insensitive LIKE search in Rails 3.1 on Heroku

How can I modify a where/like condition on a search query in Rails:
find(:all, :conditions => ["lower(name) LIKE ?", "%#{search.downcase}%"])
so that the results are matched irrespective of accents? (eg métro = metro). Because I'm using utf8, I can't use "to_ascii". Production is running on Heroku.
Proper solution
Since PostgreSQL 9.1 you can just:
CREATE EXTENSION unaccent;
Provides a function unaccent(), doing what you need (except for lower(), just use that additionally if needed). Read the manual about this extension.
More about unaccent and indexes:
Does PostgreSQL support "accent insensitive" collations?
Poor man's solution
If you can't install unacccent, but are able to create a function. I compiled the list starting here and added to it over time. It is comprehensive, but hardly complete:
CREATE OR REPLACE FUNCTION lower_unaccent(text)
RETURNS text
LANGUAGE sql IMMUTABLE STRICT AS
$func$
SELECT lower(translate($1
, '¹²³áàâãäåāăąÀÁÂÃÄÅĀĂĄÆćčç©ĆČÇĐÐèéêёëēĕėęěÈÊËЁĒĔĖĘĚ€ğĞıìíîïìĩīĭÌÍÎÏЇÌĨĪĬłŁńňñŃŇÑòóôõöōŏőøÒÓÔÕÖŌŎŐØŒř®ŘšşșߊŞȘùúûüũūŭůÙÚÛÜŨŪŬŮýÿÝŸžżźŽŻŹ'
, '123aaaaaaaaaaaaaaaaaaacccccccddeeeeeeeeeeeeeeeeeeeeggiiiiiiiiiiiiiiiiiillnnnnnnooooooooooooooooooorrrsssssssuuuuuuuuuuuuuuuuyyyyzzzzzz'
));
$func$;
Your query should work like that:
find(:all, :conditions => ["lower_unaccent(name) LIKE ?", "%#{search.downcase}%"])
For left-anchored searches, you can use an index on the function for very fast results:
CREATE INDEX tbl_name_lower_unaccent_idx
ON fest (lower_unaccent(name) text_pattern_ops);
For queries like:
SELECT * FROM tbl WHERE (lower_unaccent(name)) LIKE 'bob%';
Or use COLLATE "C". See:
PostgreSQL LIKE query performance variations
Is there a difference between text_pattern_ops and COLLATE "C"?
For those like me who are having trouble on add the unaccent extension for PostgreSQL and get it working with the Rails application, here is the migration you need to create:
class AddUnaccentExtension < ActiveRecord::Migration
def up
execute "create extension unaccent"
end
def down
execute "drop extension unaccent"
end
end
And, of course, after rake db:migrate you will be able to use the unaccent function in your queries: unaccent(column) similar to ... or unaccent(lower(column)) ...
First of all, you install postgresql-contrib. Then you connect to your DB and execute:
CREATE EXTENSION unaccent;
to enable the extension for your DB.
Depending on your language, you might need to create a new rule file (in my case greek.rules, located in /usr/share/postgresql/9.1/tsearch_data), or just append to the existing unaccent.rules (quite straightforward).
In case you create your own .rules file, you need to make it default:
ALTER TEXT SEARCH DICTIONARY unaccent (RULES='greek');
This change is persistent, so you need not redo it.
The next step would be to add a method to a model to make use of this function.
One simple solution would be defining a function in the model. For instance:
class Model < ActiveRecord::Base
[...]
def self.unaccent(column,value)
a=self.where('unaccent(?) LIKE ?', column, "%value%")
a
end
[...]
end
Then, I can simply invoke:
Model.unaccent("name","text")
Invoking the same command without the model definition would be as plain as:
Model.where('unaccent(name) LIKE ?', "%text%"
Note: The above example has been tested and works for postgres9.1, Rails 4.0, Ruby 2.0.
UPDATE INFO
Fixed potential SQLi backdoor thanks to #Henrik N's feedback
There are 2 questions related to your search on the StackExchange:
https://serverfault.com/questions/266373/postgresql-accent-diacritic-insensitive-search
But as you are on Heroku, I doubt this is a good match (unless you have a dedicated database plan).
There is also this one on SO: Removing accents/diacritics from string while preserving other special chars.
But this assumes that your data is stored without any accent.
I hope it will point you in the right direction.
Assuming Foo is the model you are searching against and name is the column. Combining Postgres translate and ActiveSupport's transliterate. You can do something like:
Foo.where(
"translate(
LOWER(name),
'âãäåāăąÁÂÃÄÅĀĂĄèééêëēĕėęěĒĔĖĘĚìíîïìĩīĭÌÍÎÏÌĨĪĬóôõöōŏőÒÓÔÕÖŌŎŐùúûüũūŭůÙÚÛÜŨŪŬŮ',
'aaaaaaaaaaaaaaaeeeeeeeeeeeeeeeiiiiiiiiiiiiiiiiooooooooooooooouuuuuuuuuuuuuuuu'
)
LIKE ?", "%#{ActiveSupport::Inflector.transliterate("%qué%").downcase}%"
)

Resources