ElasticSearch in Rails using Tire Gem on Arrays - ruby-on-rails

I am trying out Tire gem for my Demo Rails app to implement ElasticSearch.
So, here are my models associations :-
A User belongs to many UserGroups. And Every UserGroup has many Post associated with it.
So, this is what I do to show all the posts for a User in posts_controller.rb
def index
#user_groups = current_user.user_groups
for group in #user_groups
for p in group.posts
#posts = #posts.to_a.push p
end
end
end
Now, I want to add search functionality to it. A User may be able to search for a Post from all the Post that are visible to him.
So, I have two questions which are connected to each other.
Q1. How, do I add the search functionality by using the Tire gem for the User so that the user may search from the Posts that are visible to him ?
Tire allows to directly search on a model using
#posts = Post.search(params[:query])
But, I want to search from an array.
Q2. And Secondly, Is my approach correct, by first storing the concerned Posts in an array and then use Tire to search from that array ?

Related

Ransack and display by category

I want to display users based on their type, so on the user overview page I have three headers: admins / moderators / members. Under each header I show the users that are part of that group. So I query on user_type and find all users that are belonging to this group.
Each member is also works at a certain company. I'm creating a filter that uses ransack to filter on that company:
= f.input :users_company_id_in, collection: Company.order(:name), label: 'Company'
In my controller I'm using ransack like this:
def index
#q = UserType.includes(:users, :active_users).ransack(params[:q])
#user_types = #q.result(distinct: true)
end
Since in my view I'm fetching the users by using #user_types.users, this query is not respecting the ransack parameters, so I'm seeing all users for every category that has someone working for that company.
What I'm trying to achieve is obviously to see only the users that work for a specific company and only display a certain user_type if there are people in the category after filtering.
Any ideas on how to achieve this?

Rails how to use 2 of the same slugs

I am using slugs in my project to give my params an other name but I have two params called: "how-does-it-work".
(.../investor/how-does-it-work)
(.../customer/how-does-it-work)
I would like to use the slugs as how they are currently set.
Is there a way to do that?
Create two distinct routes/controllers, and simply query the corresponding ActiveRecord model in the show action. Assuming there is a slug field on your models:
Rails.application.routes.draw do
resources :customers
resources :investors
end
class CustomersController < ApplicationController
def show
#customer = Customer.find_by(slug: params[:id])
end
end
class InvestorsController < ApplicationController
def show
#investor= Investor.find_by(slug: params[:id])
end
end
This is probably the most conventional way to solve this problem in Rails. If you are using the friendly_id gem, the same approach more or less applies, except for maybe the query itself.
Hope this helps.
So, is /investor/ and /customer/ both parts of the slug?
If that's the case, you can split the string, and do a search based on the "how-does-it-work" in the grouping of "investor" or "customer".
If investor and customer are both parts of the routes, you shouldn't have a difficult time there, because they're pointing to two different controller methods. You should be able to write a search based on each of those methods that correspond to the data. If the data is the same, all your doing is pointing the controller to the correct model data with the correct params.
If you're using friendlyId, it usually has built in candidate matching. Also, if you're meaning to match multiple pages to the same slug (which I've done in the past), you can display a results page if you'd like too, by rendering based on the quantity of results.

rails cancan sunspot search not working

I am using 'sunspot_solr', '~> 2.0.0' and 'cancan', '~> 1.6.8' gems in my rails app but I can't do a successful search using those two, say I have a resource called Photos and this is my search query
photos = Photos.accessible_by(current_ability).search do
fulltext params[:query]
end.results
but the search happens on all photos not on those that belongs to current user, I believe current_user.photos and Photos.accessible_by(current_ability) are the same.
My ability.rb has this permissions
can :list, Photos
can [:read, :create, :update, :destroy], Photos, user_id: user.id
Any help would be much appreciated.
I don't think that the Sunspot search will filter based on a given scope, it just takes a model argument so it will search across all instances.
You could do the search first and then filter the results but that would mess up paging if you are using Sunspot to do that.
A better solution might be to index the user_id attribute in Solr so that you can do a search filtered by that as well as by the free text input. It isn't ideal because you would be duplicating authorisation logic.
So in your model you would need:
searchable do
...
integer :user_id
end
You would need to rebuild the search index.
And then include it in your search filter with something like:
photos = Photos.search do
fulltext params[:query]
with(:user_id).equal_to(current_ability.user.id)
end.results
There is a discussion of a similar problem here.
Even if I consider Steve answer correct you will have two different places in which you define permissions for the photos, and this is not nice because we are actually using cancan for that.
I would prefer using something like:
photos = Photo.search do
fulltext params[:query]
with(:id, Photo.accessible_by(current_ability).pluck(:id))
end.results
so you do not have to duplicate the logic for permissions.
btw: why Photos instead of Photo?

Finding data through a habtm association

I can't wrap my head around how to accomplish this and hoping that someone will be able to help - I am sure this will be something simple!
I'm trying to implement a "tag cloud" from scratch in my rails app, (fairly similar to the episode as posted on railscasts.com) with the added complexity that I only want to show tags in my "cloud", that relate to the results that are returned. For example, let's say that in the index view, the user has filtered the results. My desire is to only show tags from the filtered result set.
I have two models that contain a HABTM association between them:
class Article < ActiveRecord::Base
has_and_belongs_to_many :tags
...
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :articles
...
end
In my Article controller, I have an #articles variable which gives me the results that show in my index action. For the purpose of this explanation, let's say it's:
#article = Article.all
What I thought I'd be able to do is to call #article.tags, hoping it would return the associated tags for all articles, within the results. I thought I'd be able to then group and iterate through them, showing them in the cloud. However, this throws an "undefined method error".
I've been playing in the rails console and found that if I run:
>> #articles = Article.find(1)
>> #articles.tags
Then all tags associated with that article are returned to me. Why can't you call that on .all?
If I was to use SQL directly I'd do something like:
SELECT name, COUNT(*)
FROM tags INNER JOIN articles_tags on ... INNER JOIN articles on...
WHERE // filtered results
GROUP BY name
I guess that's a simplified equivalent of what I'm trying to do but using the rails-query-lingo.
Any ideas?
You can get the Tags that have Articles by:
Tag.joins(:articles)
Same applies for atricles that have tags.
Article.joins(:tags)
You may prefer using has_many through instead of habtm, that gives you more control over the join table, check this question

Ruby on Rails - How to Query on model/condition on controller?

I'm using rails 3.2.3 and have a questions about queries.
I've read that it is favorable using arel instead of named scopes.
Basically in my app, when a user logs in, I want him to see the products that he created.
So instead of having in my controllers index:
products=Product.find(:all)
I was looking for something like
products=Product.find(:all, :conditions....)
The thing is, my User and Product models have a HABTM relation (it really has to be) and I don't know how to join those tables so that only the products inserted by the current_user are displayed (the insertion is working correctly)
Do I have to add a search method in my Product model?
Or this can be accomplished by passing :conditions in the index controller?
Basically the logic is:
->Get all the products
->inner joining with the products_users HABTM table and get all the products where products_users.user_id = current_user.id. Return the results.
I don't know if I'm missing something here...any tips on how to code this? I'm kind of confused.
if user_sighed_in?
#products = current_user.products
else
#products = Product.scoped
end
ofc u have to define association in User model
has_many :products
If you have associated User and Products models - this code #products = current_user.products will return products of current_user.
To find all the products of current user this will do the trick
current_user.products

Resources