Filter sunspot search by class - ruby-on-rails-4

I've set up a sunspot/solr search with rails that works like a charme:
# run the search
search_results = Sunspot.search Project, Question, User, Requests do
fulltext params[:search]
paginate page: params[:page], per_page: 10
end
It could be cool to filter that search results by a given class. E.g.there is a param in the URL like params[:class], it would be awesome if the search would only consist of results from that specific class (Project, Question, User, Requests...).
I just can't figure out where to start at.
Hope someone could help me out!

Got it. All you need to do is adding the class as a string to the searchable block:
# solr search
searchable do
text :firstname, :lastname, :email, :position
integer :account_id
string :klass
end
def klass
return self.class.to_s.downcase
end
After that you're able to filter by the class (klass)
# run the search
search_results = Sunspot.search Project, Question, User do
fulltext params[:search]
with :account_id, params[:account_id]
with :klass, "question"
paginate page: params[:page], per_page: 10
end

Related

How does ransack search works on an array list?

I am using Rails 4.2.5, Ruby 2.2, ransack.
I am trying to implement search functionality using Ransack. I have something like:
emails = ["abc#abc.com", "a#a.com", "b#b.com"]
users_list = emails.map{|a| User.where(email: a).first}
checked_in_users = Kaminari.paginate_array(users_list)
This gives me proper list of users in the page. But if I want to search by email, what should I do ?
#q = checked_in_users.ransack params[:q]
This gives me:
"NoMethodError (undefined method `ransack' for #<Array"
HAML code:
= search_form_for [#q], url: users_path(some_id: id) do |form|
= form.text_field :user_name_or_user_email_cont, placeholder: 'Name or email', class: 'form-control'
What would be the correct way to do it with ransack ?
If you want to search the entire list of users, you could do something like this:
#q = User.ransack(params[:q])
#users = #q.result.page(params[:page])
You want to call ransack on your model prior to adding pagination. Once you have the ransack result, you can add pagination. This section of the documentation shows you how to handle pagination with ransack. In its most basic form, this is how you can use ransack.
Also, it looks like you have some odd code in your example. Apologies if I'm misunderstanding what you're trying to do.
When you call emails.map{|a| User.where(email: a).first}, you're making a where query 3 times in this case and returning an array of 3 models. Ransack won't operate on that array.
I would change it to something like this in your case:
emails = ["abc#abc.com", "a#a.com", "b#b.com"]
#q = User.where(email: emails).ransack(params[:q])
#checked_in_users = #q.result.page(params[:page])
Just know that you'd be searching from an array of users with emails of "abc#abc.com", "a#a.com", and "b#b.com". If you search with your ransack form for "bob#example.com", you wouldn't get any search results. This may not be what you want.

Ajax Datatables Rails - Query not working for show-method

Let's start with the database-model:
# => ProductSelection.rb
has_many :products, -> { uniq }, through: :product_variants
# => Product.rb
has_many :product_informations
belongs_to :product_configuration
belongs_to :product_class
Using plain Ruby on Rails, we collected the products to show inside the product_selection#show-method like so:
#products = ProductSelection.find(params[:id]).products.includes(:product_informations, :product_class, :product_configuration)
and generated a table like so:
= table(#products).as(:products).default do |product|
= product.name
= product.product_configuration.name
= product.product_class.name
= product.state
= link_to product_product_selection_path(#product_selection, product_id: product.id), method: :delete
Now we want to use Datatables instead of plain Ruby on Rails.
We are using the Ajax-Datatables-Rails-Gem. We would like all columns to be sortable and searchable in the end.
Unfortunately we do not come past the query to retrieve the Products belonging to the ProductSelection in question.
This is the query we tried so far:
def get_raw_records
ProductSelection.find(params[:id]).products.includes(:product_informations, :product_class, :product_configuration).references(:product_information, :product_class, :product_configuration).distinct
end
def data
records.map do |record|
[
record.name,
record.product_configuration.name,
record.product_class.name,
record.state,
record.id
]
end
end
The error that pops up:
> undefined method `each_with_index' for nil:NilClass
When adding in sortable/searchable columns, the error is the following instead:
PG::UndefinedColumn at /product_selections/fetch_table_data_show.json
=====================================================================
> ERROR: column products.name does not exist
LINE 1: SELECT DISTINCT "products"."id", products.name
with the configuration like so:
def sortable_columns
# Declare strings in this format: ModelName.column_name
#sortable_columns ||= %w(Product.name ProductConfiguration.name ProductClass.name Product.state)
end
def searchable_columns
# Declare strings in this format: ModelName.column_name
#searchable_columns ||= %w(Product.name ProductConfiguration.name ProductClass.name Product.state)
end
I think the problem is with the different models right here. I assume Datatables-Rails expects a model of ProductSelection but instead is prompted with a Product. Any help would be highly appreciated!
If anything is missing, let me know!
After having another look at this, we figured the problem was that Product.name wasn't a valid ActiveRecord-construct. Instead it was a helper method defined somewhere down the road.
Since the gem tries to find records through the column-names, this error occurred.
We solved it by removing the column in question. Other approaches would be to:
Store the data in a separate column, instead of using a helper.
Implementing the helpers behavior in javascript so that we can pass
it as a callback to datatables.

Rails 4 Dynamically Generate an Extra Public-Facing URL on Create

I have a Rails app that stores stock photos in each project. Upon creating a project, I want the app to not only create the url for the project that we will view internally, which is projects#show,i.e. /projects/4 but I also want it to create another URL that we can show to the client that will be a little different. It will allow the to approve the photos, etc. I want the url to be something like /projects/st53d where the end of the url will be a random number generated with random_string = SecureRandom.urlsafe_base64(5)
This way, I can pass this url to the clients and they can view all the photos in the project and approve the ones they want us to use, but cannot change or view the other internal stuff we have on the standard product show page
Currently, I have added a client_url column to the Project model and I was thinking of generating the random number within the Project#create method and then saving it to the project's client_url column. This way I can loop through all client urls and make sure I did not generate a duplicate. But I cannot figure out how to do the route creation part.
i have yet to do the part where I check if it is random but I know how to do that, just not the route creation.
I was thinking I needed to create a new method which I named show_client and somehow create a route for that in my config/routes.rb file
class ProjectsController < ApplicationController
before_action :authenticate_user!, only: [:show,:index]
def create
#project = Project.create(project_params)
#project.creator = current_user.email
require 'securerandom'
random_string = SecureRandom.urlsafe_base64(5)
#project.client_url = random_string
#project.save
redirect_to #project
end
def show_client
#project = Project.find(params[:id])
#photos = #project.photos
end
This seems like more of a roles issue. You could check out something like CanCanCan. If you only need two kinds of users, you could also just add a boolean column for admin to your user table. The url extension doesn't seem to matter in the scope of your problem. If you want to use a different view for the visiting the user show page, something in the show action like:
unless current_user.admin?
redirect_to client_show(current_user.id)
end
I was able to figure it out.
I created the client_url column in the database and upon creating a project, in the create method of the projects_controller, I generated a random base64 number and assigned it to project.client_url
in routes.rb i did:
get 'projects/clients/:client_id' => 'projects#clients', as: 'projects_client'
in my projects_controller.rb:
def clients
#project = Project.where(client_id: params[:client_id])
end
then the link to that route is:
<%= link_to 'Client Version', projects_client_path(#project.client_url) %>

Pass two params in a Rails Controller

I'm working on a project that requires a third party (not a registered user of my application) to follow an email link to update a document. I've created a :token column for each entry, and have it successfully appended to the email link using:
edit_form_url(:id => #form.id, :token => #form.token)
My problem is trying to reference the additional param in my controller using this code:
def edit
#form = Form.find(params[:id],[:token])
redirect_to pages_error_path if #form.sign.present?
end
When using the above code, I get a Couldn't find all Forms with 'id': (193, token) (found 1 results, but was looking for 2) error. Can anyone help me figure out what I'm doing wrong?
It seems I may have solved my own problem, posting it for Google and error checks:
def edit
#form = Form.find_by(token: params[:token], id: params[:id])
redirect_to pages_error_path if #form.sign.present?
end

Rails 4 - Column exists but does not update

I have recently added a field "tag" to my blog app built in Rails 4. Below you can see the field appearing in the Edit view:
But once I return to the Show view after editing, this does not appear:
When I check the database directly I can definitely see it exists:
sqlite> PRAGMA table_info(POSTS);
0|id|INTEGER|1||1
1|title|varchar(255)|0||0
2|body|text|0||0
3|created_at|datetime|0||0
4|updated_at|datetime|0||0
5|slug|varchar(255)|0||0
6|tag|varchar(255)|0||0
Can anyone suggest what is going on or how to troubleshoot this?
Rails 4 uses strong parameters by default. This means you have to explicitly whitelist params you wish to mass assign.
When adding a new attribute to a model, you have to remember to update the permitted params in you controller.
For example, in your case, you would need to make sure :tags are added like so:
class PostController < ActionController::Base
def update
post = Post.find(params[:id])
post.update(post_params)
redirect_to post
end
private
def post_params
params.require(:post).permit(:title, :body, :tag)
end
end