If search on model has no hits, invoke javascript file - ruby-on-rails

I make an search on an model:
def self.search(search)
if search
where('Bezeichnung LIKE?', "%#{search}%")
else
all
end
end
What i would like to change, is that when the search has no hits it fires an javascript file in icd/index.js.erb
Index.js.erb:
$('#chapter_list').html("<%= escape_javascript(render(:partial => 'icd1')) %>");
How can i do this?

Presumably this class method (self.search) is on a model. Since your controllers are where you return responses from, you'd need to have your controller respond with javascript code.
Something like:
def index
results = Model.search(params[:search])
respond_to |format| do
if results
format.html { render 'index.html.erb' }
else
format.js { render 'index.js.erb' }
end
end
end

i would do something like this, i would create another model method, like this:
Model:
def checkSearch(search)
if search
where('Bezeichnung LIKE?', "%#{search}%")
end
end
controller
#checker= Model.checkSearch(search)
in the view you can check if #checker is different from null and redner the partial
I know this aproach will query the database twice, but is a start.
more thought on it you can return an array in you first model method with a bollean in the first position and the active record object in the second one.
hope i gave you some direction!

Related

active admin how to render form on index page if object not created

I can't understand what I do wrong. My code won't work if subscription blank, but if I created it from rails c, all works fine...
# frozen_string_literal: true
ActiveAdmin.register Subscription do
actions :index
index do
result = Subscriptions::GetPricing.call(admin: current_admin)
if result.success?
render partial: 'subscription_form', locals: { amount: result.plan.amount }
else
flash[:alert] = result.message
render partial: 'subscription_errors'
end
end
end
Now i get: There are no Subscriptions yet. simple message.
And i want left all styles, nav panel, etc how it default, but in container should be store my code from partials.
If your intent is to display an input form if the table is unpopulated then try this:
controller do
def index
collection.size == 0 ? redirect_to(new_subscription_path) : super
end
end
I think what you are trying to do is a bit wrong. index do block is to render the view level mainly. If you want to override controller action you will have to do it like below -
controller do
def index
# your code here
end
end
Have a look at the documentation -
https://activeadmin.info/8-custom-actions.html
https://activeadmin.info/3-index-pages.html

How to build a query in a controller but only make one db call

My idea for an #index method of a controller is to set things = Thing.all and then if there are filter params, check for them one by one and chain them on so that at the end, you're left with a single query to execute. But the following queries get executed as they are called:
def things_controller
def index
things = Thing.all #<-- db call #1
if params[:color]
things = things.where(color: params[:color]) #<-- db call #2
end
render json: things #<-- I would like to make a single db call here instead
end
end
How can I prevent multiple unnecessary db calls? Is there some convention for filter params that I should be using?
You just need to reorganise the code like this:
def index
things = if params[:color]
Thing.where(color: params[:color])
# ...else if
else
Thing.all
end
render json: things
end
Updated
If you want to chain where clauses, do this:
def index
valid_params_keys = %w(color size)
filtered_keys = valid_params_keys.select { |key| params.keys.include?(key) }
# Don't need conditional check anymore :).
#products = filtered_keys.inject(Product.all) do |scope, key|
scope.where(key => params[key])
end
end
Since things is an array, you can do this, which is only an array operation.
def index
things = Thing.all
if params[:color]
things = things.select!{ |thing| thing.color == params[:color]}
end
render json: things
end

ActiveRecord serialize two different models in at once

I have a controller action (favorites) in my Rails app that returns a JSON object with two keys (companies and jobs). Each key represents a collection of Company or JobDescription objects. What I want to know is if there is a clean way I can serialize both #companies and #jobs. Here is my code:
def favorites
#companies = current_user.companies
#jobs = current_user.job_descriptions
respond_to do |format|
format.html
format.json { render json: {companies: #companies, jobs: #jobs}, root: false }
end
end
I could always refactor my code into two separate JSON calls (one for jobs, one for companies), but I'd prefer to stick with a single call to favorites.
You can use Rails Presenters here!
So, you can have two presenters: CompaniesPresenter and JobsPresenter which will be responsible for building the #companies and jobs objects respectively.
So, in your controller, you would have something like:
#companies = CompaniesPresenter.new(current_user).companies
#jobs = JobsPresenter.new(current_user).job_descriptions
For example, your CompaniesPresenter would look like this:
class CompaniesPresenter
attr_reader :current_user
def initialize(current_user)
#current_user = current_user
end
def companies
# build the companies JSON here
end
end
Here is a tutorial with Rails Presenter Pattern that might be useful.
And, here is an useful video. Hope this helps.
This example works, are you just trying to change the json format? If so...
In the company or job model, you can add an as_json method and format the output as you want.
def as_json(options = {})
{ :name => name }
end

Rails Controller Model Object Passing

This is more of an architecture/functional question for Rails. I have a search function which sends the criteria to the model where the query resides. The search works. Now I have a CSV export link <%= link_to "CSV", contacts_path(format: "csv") %> in my view file which points to localhost/books.csv.
The export didn't work without my search parameters (so localhost/book.csv?book_name=foo works as expected). What I do in send_data is I pass the #books object to the .to_csv function inside my model, and it becomes nil without passing the parameter also. Pls see code below.
My controller:
def index
#books = Book.search(params[:search])
respond_to do |format|
format.html
format.csv { send_data Book.to_csv(#books) }
end
My model:
def self.search(criteria)
find(:all, :conditions => ['book_name LIKE ?', "%#{criteria}%"])
end
def self.to_csv(search_results)
CSV.generate do |csv|
csv << column_names
search_results.each do |contact|
csv << contact.attributes.values_at(*column_names)
end
end
end
I like to understand why. The current setup seems to be making another request to the server in order to generate the CSV file, and that's why it requires the parameters in localhost/books.csv request. Is this correct?
Now, if instead I put the query inside the controller like below, the CSV request works as expected (so I just click the link and receive the file).
def index
#books = Book.find(:all, :conditions => ['book_name LIKE ?', "%#{criteria}%"]) respond_to do |format|
format.html
format.csv { send_data Book.to_csv(#books) }
end
I love to keep the query inside the model for the sake of organization, so would be awesome if you guys can point me to the right direction. Thanks!
I would suggest that you change your link to something like this:
<%= link_to "CSV", contacts_path(params.merge(format: "csv")) %>
This will pass down the current search parameters plus the new option for the format to be CSV. Then you can continue to keep the search method inside the model in the way that you had originally written it.

Custom method redirect in Rails

I've created a custom method in my model, which finds a record by name:
def find_city
Place.find_by_name(city_name)
end
I can call this method in my view with place_path(#place.find_city), which works great when a place with the appropriate name exists. What I would like to be able to do is write in a redirect for when the place doesn't exist, and I'm unsure about where the logic should go. Basically, I would like to write something like:
respond_to do |format|
if #place.find_city.blank?
format.html { redirect_to :action => "new" }
else
format.html { render :action => "show" }
end
end
...but I would still like the controller to respond to place_path(#place) in the usual manner as well. Any help would be much appreciated!
EDIT: sorry for the confusion, should have explained my example further. I have a Place model that has both 'city_name' and 'name' as attributes. The find_city custom method that I detailed above finds the place whose name matches the city_name for another place eg.
Place.name = "foo"
Place.city_name = "baz"
So therefore Place.find_city gives the record where Place.name = "baz". Cheers!
Do something like this
keep your model as
class City < ActiveRecord::Base
named_scope :by_name, lambda {|city|{:conditions => "name=#{city}"}}
end
in your controller
class CitiesController < ApplicationController
def index
#city = City.by_name(<city name>)
if #city.nil?
<redirect to one place>
else
<redirect to another place>
end
end
end
and in your view access the #city parameter.
** Normally we shouldnt access Models directly from views. Either we should do it through controllers or helpers
Hope this helps
cheers
sameera
I've decided to create a helper method for this problem - what I've described above might seem a bit of an unorthodox approach, but I only need the find_city method to create a links bar for each place, so I don't think I really need to create a separate city model, or define a formal self-referential relationship. Just in case anyone might find this useful, I've created a links_bar helper:
module PlacesHelper
def links_bar(place)
if place.city_name.blank?
render "no_city_links"
elsif place.find_city.nil?
render "nil_find_city_links"
else
render "complete_links"
end
end
end
Each partial then has the required behaviour depending upon whether or not the find_city method returns a record or not.

Resources