I have been using the information here (http://ngauthier.com/2013/08/postgis-and-rails-a-simple-approach.html) so that the search results in my app can be shown based on proximity.
I am listing all tasks with their associated project information - a project can have multiple tasks.
I have the following AR query in my Project controller:
#results = Task.select('tasks.*') # .select('tasks.*') required for pg_search
.joins(:project => :user)
.includes(:project => :user)
.merge(Project.enabled_only.filter_by_location(#geo).search(params[:q]))
.order_results(sort)
In my Project model I have:
scope :distance_from, ->(latitude, longitude) {
select(%{
ST_Distance(
ST_GeographyFromText(
'SRID=4326;POINT(' || projects.longitude || ' ' || projects.latitude || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)')
) AS distance
} % [longitude, latitude])
}
scope :near, ->(latitude, longitude, distance_in_meters = 1000) {
where(%{
ST_DWithin(
ST_GeographyFromText(
'SRID=4326;POINT(' || projects.longitude || ' ' || projects.latitude || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
%d
)
} % [longitude, latitude, distance_in_meters])
}
def self.filter_by_location(geo_location)
scoped = self.all
if geo_location.present?
scoped = scoped.distance_from(geo_location[:lat], geo_location[:lng])
scoped = scoped.near(geo_location[:lat], geo_location[:lng])
end
scoped
end
I then have the following in my Task model:
scope :distance_order, -> { order('distance') }
def self.order_results(sort)
# order scopes are appended
scoped = self.all.reorder('')
# check sql for search and distance fields
search_performed = scoped.to_sql.downcase.include?(' pg_search_rank')
distance_calculated = scoped.to_sql.downcase.include?(' distance')
if sort == 'rel'
# rel,dist
scoped = scoped.search_rank_order if search_performed
scoped = scoped.distance_order if distance_calculated
else
# dist,rel
scoped = scoped.distance_order if distance_calculated
scoped = scoped.search_rank_order if search_performed
end
scoped = scoped.name_order
scoped
end
This works fine for my app to sort results by proximity.
Distance is one of the columns in the sql select produced by the AR query, along with tasks.* and distance is being used correctly to sort results but I'm not sure how to display the distance in my view.
If I do <%= result.distance.to_s %>, it says distance is an undefined method. I don't have any joy with <%= result.project.distance.to_s %> either. Whereas <%= result.task_field %> and <%= result.project.project_field %> work fine.
I haven't seen too much use of both .joins() and .includes() at the same time in the RoR world but it did allow me to reduce the number of db calls whilst still producing the correct sql select statement...in my case anyway - that's why they are both used.
Am I missing something?
Is it the complexity of my AR query causing it?
Am I missing something in my Project or Task model to allow the virtual/calculated distance field to be display-able?
Thanks
The complex structure was replaced by a database view.
More details of how to do this can be found at this tutorial (http://pivotallabs.com/database-views-performance-rails/) and in one of my other SO questions here (Connecting database view with polymorphic model in rails).
Related
i am trying to put 2 queries together in a scope - i am unsure where i am going wrong. your advise would be much appreciated
I want to displays only users whose status is stated as "Accepted" or "nil"
i wrote the below scope and tried others but no success
scope :active_recruiters, -> {where(['status = ? OR status = ?', 'Accepted', 'IS NULL'])}
If you want to chain with OR instead of AND user AREL table constraint
scope = where( where(status: 'Accepted').arel.constraints.reduce( :and ).or( where(status: nil).arel.constraints.reduce( :and ) ) )
Try scope :active_recruiters, -> { where(status: ['Accepted', nil]) }
the query that you're trying to curate would look like this:
WHERE status = 'Accepted' OR status = 'IS NULL';
You're probably looking for something like this instead:
WHERE status = 'Accepted' OR status is null;
try this in your code
scope :active_recruiters, -> {where(['status = ? OR status ?', 'Accepted', 'IS NULL'])}
Even better though, how about this?
scope :active_recruiters, -> { where :status, [nil, 'Accepted'] }
I have radiobuttons creaated in loop.
- #annual_packages.each do |plan|
= f.radio_button('plan_id', plan.id)
= plan.title
How can I make condition to check radio if plan.id == #plan.id
Doesn't work:
= f.radio_button('plan_id', plan.id, checked: (plan.id == #plan.id))
Loop code:
= form_for #organization, url: subscription_create_path, remote: true, method: :post do |f|
- unless #annual_packages.blank?
- #annual_packages.each do |plan|
= f.radio_button('plan_id', plan.id)
= plan.title
Can you post your form_for code?
Cause if your column plan_id have any value, it should be checked automatically if it matches the tag_value`.
If the current value of method is tag_value the radio button will be
checked.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-radio_button
If you are using simple_form or form_for, and f is your form object then you can simply do:
for form_for:
radio_button(object_name, method, tag_value, options = {}) refer
in your case:
- #annual_packages.each do |plan|
radio_button("your object name", "plan_id", plan.id, options = {})
If the current value of method(object.plan_id) is tag_value(plan) the radio button will be checked.
for simple_form:
= f.input :plan_id, as: :radio_buttons, collection: #annual_packages
besides using devise for authentification w standard Devise routes.. , I added the follwoing
namespace :users do
resources :todos
end
to magane todos for the current user.
the generated routes are fine ...
users_todos GET /users/todos(.:format) users/todos#index
POST /users/todos(.:format) users/todos#create
new_users_todo GET /users/todos/new(.:format) users/todos#new
edit_users_todo GET /users/todos/:id/edit(.:format) users/todos#edit
users_todo GET /users/todos/:id(.:format) users/todos#show
PATCH /users/todos/:id(.:format) users/todos#update
PUT /users/todos/:id(.:format) users/todos#update
DELETE /users/todos/:id(.:format) users/todos#destroy
once the user is logged in , he is redirected to his todos#index list .. (users_todos_url)
def after_sign_in_path_for(resource)
....
elsif resource.is_a?(User) && Settings.permit_user_login
stored_location_for(resource) || users_todos_url
....
but then , the error is raised .... and it's stated in the log :
Started GET "/users/todos" for 127.0.0.1 at 2014-07-22 14:29:15 +0200
LoadError - Unable to autoload constant Users::TodosController, expected /Users/yves/bitbucket/railsTests/todoapp/app/controllers/users/todos_controller.rb to define it:
I have a users/todo_controller.rb
class User::TodosController < ApplicationController
..
def index
sort_order = "updated_at DESC , title"
todos = Todo.where(:user_id => current_user[:id]).order(sort_order).page params[:page]
end
Log says todo s _controller.rb.
Controller names are plural form.
To allow me to quickly filter records in ActiveAdmin i've defined scopes on my model. I have "shipped" and "unshipped" scopes as below. For some reason the "Shipped" scope is working as expected and shows the number of shipped items but the "Unshipped" scope doesn't do anything, it doesn't seem to know what is unshipped. It seems that i have to check and then uncheck "Shipped" checkbox in order for it to know that it's unshipped??
ORDER MODEL
class Order < ActiveRecord::Base
scope :shipped, where(:shipped => true)
scope :unshipped, where(:shipped => false)
end
ADMIN ORDER MODEL
ActiveAdmin.register Order do
scope :all, :default => true
scope :shipped
scope :unshipped
index do
selectable_column
column "Status", :sortable => :shipped do |s|
status_tag((s.shipped? ? "Shipped" : "Unshipped"), (s.shipped? ? :ok : :warning))
end
end
end
Can anyone see what the problem is?
Many Thanks
Is that the actual code from your model?
It should be:
scope :shipped, -> { where(shipped: true) }
scope :unshipped, -> { where(shipped: false) }
Realised that shipped was not by default set to false so fixed the issue by doing so in the Orders table.
Is it possible to show modules in Joomla only in a specific article (not per menu item), but in standard module position?
For example somehow get the current article id in a template and insert the modules with according id suffix in the name?
I would advise you not to hardcode things like this in the template. My question is, why don't you want to use a menu item? You can create a hidden menu item for that article and use it, then assign the module to that menu item.
If you still want to do it without using a menu item, a possible workaround would be to use something like "mod_php" (some module that allows you to use php code) and do something more or less like this:
Create the module and assign it to a position that is not used anywhere (you can type whatever you want in the module position)
In your php module, put this code:
$option = JRequest::getVar( 'option', '' );
$view = JRequest::getVar( 'view', '' );
$id = JRequest::getInt( 'id', 0 );
if ( $option == "com_content" && $view == "article" && $id == YOUR_ARTICLE_ID ) {
$module = JModuleHelper::getModule('your_module_type', 'module_title');
if ( ! empty( $module ) ) {
$attribs = array( 'style' => 'xhtml' );
echo JModuleHelper::renderModule( $module, $attribs );
}
}
I'm sorry if the code snippet is not showing properly, but I hope you can read it ok. Just one thing, when you fill in the part saying 'your_module_type', don't include the "mod_" part of the name. For example, if you want to output a module of type "mod_article_list", you should write "article_list" in "your_module_type".
I hope it helps!