How to add an AND condition to SQL query - sql

I am trying to add an AND condition where active = true is also incorporated within an SQL query inside of rails.
Schema.rb
...
create_table 'relationships', force: :cascade do |t|
t.integer 'follower_id'
t.integer 'followed_id'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.boolean 'active', default: true
t.index ['followed_id'], name: 'index_relationships_on_followed_id'
t.index %w[follower_id followed_id], name: 'index_relationships_on_follower_id_and_followed_id', unique: true
t.index ['follower_id'], name: 'index_relationships_on_follower_id'
end
...
user.rb
...
def feed
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id AND active = true"
View.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id).includes(:user)
end
...
However the addition of AND active = TRUE does not seem to work to pull followed_ids with follower_id as self and where the active boolean is true.

Managed to solve it by assigning an active within the query.
...
def feed
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id AND active = :active"
View.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id, active: true).includes(:user)
end
...

Related

How to search-query ActiveRecord Associations (.joins) with SQL ILIKE

I am trying to query multiple Active Record-Models by passing query-params to a Controller. Within my tales_controller.rb I have the following index-method:
def index
#tales_count = Tale.all.count
if params[:search]
#tales = Tale.joins(:category)
.where('category.title ILIKE ?', "%#{params[:search]}%")
.where(
'title ILIKE :search OR
subtitle ILIKE :search OR
short_description ILIKE :search', search: "%#{params[:search]}%"
)
else
#tales = Tale.all
end
render template: 'tales/index'
end
Now, I can't seem to figure out the correct solution to this problem, as for the most part PG throws an error, saying: PG::AmbiguousColumn: ERROR: column reference "title" is ambiguous. I sense that this is due to the fact that I try to query the title-field on the Tale-, as well as on the Category-Model. However I am not able to fix this problem myself.
By providing the index-method with the right queries I expect to be able to query a couple fields on the Tale-Model (namely title, subtitle and short_description and potentially more), as well as the title-field on the Category-Model.
The Category-Model is referenced by the Tale-Model. This is what the schema.rb looks like:
create_table "tales", force: :cascade do |t|
t.string "public_id"
t.string "title"
t.string "subtitle"
t.string "player_count"
t.string "short_description"
t.datetime "published_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "category_id"
t.bigint "author_id"
t.index ["author_id"], name: "index_tales_on_author_id"
t.index ["category_id"], name: "index_tales_on_category_id"
end
EDIT: uhm, I just realized that by querying the way I currently do, I expect the category.title AND any of the other Tale-fields to carry the search-term. This is not want I intended, frankly.
Table name in Rails are by convention in the plural. So change this to read
.where('categories.title ILIKE ?', "%#{params[:search]}%")
and just for fun ILIKE in Postgres can be written as
.where('categories.title ~* ?', params[:search])

How to search my DB for specific m to n relations saved in a jointable

I am using a postgreSQL DB on my Rails app. I have established m-to-n relationships between Slots and Hashtags. The last thing I need is to find Slots who match specific Hashtags given per url params
Here is the schema.rb
create_table "hashtags", force: :cascade do |t|
t.string "value"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "hashtags_slots", id: false, force: :cascade do |t|
t.bigint "hashtag_id", null: false
t.bigint "slot_id", null: false
t.index ["hashtag_id"], name: "index_hashtags_slots_on_hashtag_id"
t.index ["slot_id"], name: "index_hashtags_slots_on_slot_id"
end
create_table "slots", force: :cascade do |t|
t.string "slot_name"
t.string "file_path"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["slot_name"], name: "index_slots_on_slot_name"
end
I want to show the Index of the slots filled with slots who have one of the hashtags that is given through the params[:hashtags]. The value of Hashtags can contain 1 or more Strings like so:
hashtags = "NetEnt PlayNGo Novomatic"
This is inside the index action of the Slot controller
if(params[:slot_name])
#slots = Slot.where(slot_name: params[:slot_name]).paginate(page: params[:page])
elsif(params[:hashtags])
#slots = slotsWithAtLeastOneOfThose(params[:hashtags])
else
#slots = Slot.all.paginate(page: params[:page])
end
How should a method
slotsWithAtLeastOneOfThose(hashtags)
slots = ...
return slots
end
look like to give me all the Slotsthat have at least one hashtag in the hashtags variable
Consider those relations:
Slot table:
id: 1 slot_name: Book of Dead
id: 2 slot_name: Big Win Cat
id: 3 slot_name: Big Bad Wolf
Hashtag table:
id: 1 value: PlayNGo
id: 2 value: Fun
id: 3 value: NetEnt
id: 4 value: MicroGaming
id: 5 value: NotFun
Hashtags_Slots table would look like this:
slot_id hashtag_id
1 1
1 2
2 2
2 3
2 5
3 4
3 5
And now the method
slotsWithAtLeastOneOfThose("PlayNGo NetEnt")
should give me all the Slots with the Hashtag PlayNGo and NetEnt
In this case
id: 1 slot_name: Book of Dead
id: 2 slot_name: Big Win Cat
Please check below query for getting slots with particular hash tag value
if(params[:slot_name])
#slots = Slot.where(slot_name: params[:slot_name]).paginate(page: params[:page])
elsif(params[:hashtags])
#slots = Slot.joins(:hashtags).where("hashtags.value LIKE ?", "%#{params[:hashtags]}%")
else
#slots = Slot.all.paginate(page: params[:page])
end

How can I call the id number of a supplier, that is in a link, call it from a controller

I have two tables, proveedors (suppliers) and productos (products).
Also I have a controller, in_stock_proveedors. In this view I show the list of all proveedors, all this proveedors has a link, where I call its id.
I would like know how can I call this id proveedors, from the link that I have in index (in_stock_proveedors), to proveedors controler.
This is my routes.rb file:
resources :productos
resources :proveedors
resources :in_stock_proveedors
devise_for :usuarios
get "/stock_proveedors", to: "proveedors#get_stock"
This is the link, that I have in_stock_proveedors, where from where I call
the id of the proveedor that I choose:
link_to "Ir al proveedor", stock_proveedors_path(:value =>{:id=>item['proveedors.id']})
This the method, in proveedors controller, where I want to receive the id number from the link, with the param p
def get_stock
#p = Proveedor.find(params[:id])
sql = 'SELECT productos.id as producto, productos.nombre as nombre
FROM productos
INNER JOIN proveedors ON productos.proveedor_id = proveedors.id
WHERE productos.proveedor_id = #p
GROUP BY productos.id'
#aux= ActiveRecord::Base.connection.execute(sql)
end
This is the index, of in_stock_proveedors
item['proveedors.id'])%>
This is the in_stock_proveedors controller
def index
sql3= "SELECT
proveedors.nombre as proveedor,
COUNT(productos.id) as distintos,
COUNT(CASE WHEN productos.stock > '0' THEN productos.id END) as instock,
proveedors.id
FROM proveedors
INNER JOIN productos ON proveedors.id = productos.proveedor_id
GROUP BY proveedors.id"
#aux3= ActiveRecord::Base.connection.execute(sql3)
end
This is the schema,for proveedors
create_table "proveedors", force: :cascade do |t|
t.string "nombre"
t.string "direccion"
t.string "email"
t.string "telefono"
t.string "rut"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "pais"
t.string "pagina_web"
t.integer "producto_id"
t.integer "orden_de_compra_id"
t.index ["orden_de_compra_id"], name: "index_proveedors_on_orden_de_compra_id"
t.index ["producto_id"], name: "index_proveedors_on_producto_id"
end
Assuming your controller action for the index page is something like
def index
sql = 'SELECT * FROM proveedors'
#proovedors = ActiveRecord::Base.connection.execute(sql)
end
loop through the #proovedors list in your index view file;
<% #proovedors.each do |proveedor| %>
<%= link_to "Ir al proveedor", stock_proveedors_path(:id => proveedor['id']) %>
<% end %>
Then, access params[:id] in your controller action
def get_stock
#p = Proveedor.find(params[:id])
...
end

"Flexible"(?) Rails Database

I'm not sure if the title is clear. I'm not too sure what the kind of answer I'm looking for is called. I've been searching and searching and can't seem to find the answer.
Here's what I want to do:
I want a user to create a workout consisting of x sets, x reps, and x type.
I know I can do for example;
create_table "workouts", :force => true do |t|
t.string "workout name"
t.integer "sets"
t.integer "reps"
t.string "type"
end
But in this method, it only allows one type of set to be written/workout.
I want the ability to add multiple types of sets/workout.
So for example;
workout name: monday morning
sets: 2 reps: 4 type: "bicep curl"
sets: 4 reps 23 type: "bench press"
etc..
If my explanation is too unclear or if maybe I'm just confused please feel free to point out. All help is appreciated. Thanks for viewing!
You should create a table workouts and workout_details and link them together:
create_table "workouts", :force => true do |t|
t.string :name
end
create_table "workout_details", :force => true do |t|
t.references :workout
t.integer :sets
t.integer :reps
t.string :type
end
And your models would look something like this:
class Workout < ActiveRecord::Base
has_many :workout_details
end
class WorkoutDetail < ActiveRecord::Base
belongs_to :workout
end
If you set it up like this, you create several workout details:
bicep_curl = WorkoutDetail.new
bicep_curl.type = 'bicep curl'
bicep_curl.sets = 2
bicep_curl.reps = 4
bicep_curl.save
bench_press = WorkoutDetail.new
bench_press.type = 'bench press'
bench_press.sets = 4
bench_press.reps = 23
bench_press.save
and add them to a workout:
workout = Workout.new
workout.name = 'monday morning'
workout.workout_details << bicep_curl
workout.workout_details << bench_press
workout.save
To retrieve your workout, you can do this:
workout = Workout.where(:name => 'monday morning').first
puts "workout name: #{workout.name}"
workout.workout_details.each do |wd|
puts "sets: #{wd.sets} reps: #{wd.reps} type: #{wd.type}"
end
Output:
workout name: monday morning
sets: 2 reps: 4 type: bicep curl
sets: 4 reps: 23 type: bench press

Rails - how to select all records by ID range

I am trying to do a query for all cities (selecting only their name attribute) by their ID, and I want to be able to specify a range of ID's to select. My code is below:
def list_cities(start, stop)
cities = City.all(order: 'name ASC', id: start..stop, select: 'name')
cities.map { |city| "<li> #{city.name} </li>" }.join.html_safe
end
However, I get an error:
Unknown key: id
My implementation in my view is:
<%= list_cities(1,22) %>
This is a helper method to be put in all views, so I am not putting the logic in a particular controller.
My schema for this model is:
create_table "cities", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "neighborhoods"
t.string "name"
t.integer "neighborhood_id"
end
When I ran the method in my console, I got:
City Load (0.9ms) SELECT name FROM "cities" WHERE ("cities"."id" BETWEEN 1 AND 3) ORDER BY name ASC
=> ""
I know it's not an issue of having an empty database since it worked with the following version of the method:
def list_cities(start, stop)
cities = City.all(order: 'name ASC', limit: stop - start, select: 'name')
cities.map { |city| "<li> #{city.name} </li>" }.join.html_safe
end
However, this method returns only the first 'n' records and not a range like I want.
When trying a simpler query in the console:
1.9.3p385 :009 > City.where(:id => 1..4)
City Load (0.9ms) SELECT "cities".* FROM "cities" WHERE ("cities"."id" BETWEEN 1 AND 4)
=> []
I figured out why it was happening...
I did City.all in my console and realized that my cities started with id "946" because I had seeded multiple times and the ID's were not what I thought they were! The solution offered was correct!
City.where(:id => start..stop).order('name ASC').select(:name)
You can turn your query to the following:
cities = City.all(order: 'name ASC', conditions: { id: start..stop }, select: 'name')
Speransky Danil's answer should work perfectly. you can try this too:
City.find((start..stop).to_a,:select=>:name,:order=>'name ASC')