Conditional issue using relationship - ruby-on-rails

I'm trying to search a column from another table using three tables in relationship.
In my view policy_vehicles I have a text_field_tag and want to search by "raz_soc".
My tables are:
Policy_vehicles
|id| |policy_id|
integer integer
100 1
200 2
Policies
|id| |client_id|
integer integer
1 1
2 2
Clients
|id| |raz_soc|
integer varchar(255)
1 MARATEX SAC
2 ATT
This is my controller:
class PolicyManagement::PolicyController < ApplicationController
def generate_print_per_vehicle
params[:search_policy_id] = Policy.find(:all,:joins => :client ,:conditions => ['raz_soc LIKE ?',"%#{params[:search_raz_soc]}%" ])
#policies= PolicyVehicle.find(:all,:joins => :policy, :conditions => ['policy_id = ?',params[:search_policy_id] ])
end
end
This is my model:
class Policy < ActiveRecord::Base
belongs_to :client
has_many :policy_vehicles
end
class PolicyVehicle < ActiveRecord::Base
belongs_to :policy
end
class Client < ActiveRecord::Base
has_many :policies
end
This is my view where I'm trying to find by a column from another table:
<% form_tag :controller=>"policy_management/policy",:action=>"generate_print_per_vehicle" do %>
Society:
<%= text_field_tag "search_raz_soc",params[:search_raz_soc] %>
<%= submit_tag "Buscar", :name => nil %>
<% end %>
My logs are:
Mysql::Error: Operand should contain 1 column(s): SELECT `policy_vehicles`.* FROM `policy_vehicles` INNER JOIN `policies` ON `policies`.id = `policy_vehicles`.policy_id WHERE (policy_id = 166,1540,2822,4074)
It should be a search like this:
Policy Load (3.1ms) SELECT `policies`.* FROM `policies` INNER JOIN `clients` ON `clients`.id = `policies`.client_id WHERE (raz_soc = 'MARATEX SAC')
PolicyVehicle Load (0.3ms) SELECT `policy_vehicles`.* FROM `policy_vehicles` INNER JOIN `policies` ON `policies`.id = `policy_vehicles`.policy_id WHERE (policy_id = 1)
I tried this but is not working:
#controller
#policy = Policy.find(:all,:joins => :client ,:conditions => ['raz_soc LIKE ?',params[:search_raz_soc] ])
#policies= PolicyVehicle.find(:all,:joins => :policy, :conditions => ['policy_id = ?',#policy ])
#logs
Policy Load (3.1ms) SELECT `policies`.* FROM `policies` INNER JOIN `clients` ON `clients`.id = `policies`.client_id WHERE (raz_soc = 'MARATEX SAC')
PolicyVehicle Load (0.3ms) SELECT `policy_vehicles`.* FROM `policy_vehicles` INNER JOIN `policies` ON `policies`.id = `policy_vehicles`.policy_id WHERE (policy_id = 70353610714140)
I'm trying to do something like this
select * from policy_vehicles where policy_id
IN ( SELECT id FROM policies WHERE
client_id IN (SELECT id FROM clients raz_soc = ?) )
Can someone can help me please?

Try this (I have explained what the queries return so make sure that this is what you want from them)
#policies = Policy.find(:all,:joins => :client ,
:conditions => ['raz_soc LIKE ?',"%#{params[:search_raz_soc]}%"] )
# returns an array of policy records based on the raz_soc condition on client
#policy_vehicles = PolicyVehicle.find(:all,:joins => :policy,
:conditions => ['policy_id IN (?)',#policies] )
# returns an array of policy_vehicles that are associated with any record in the #policies array
Other option is to do it in a single query as:
#policy_vehicles = PolicyVehicle.joins(:policy => :client).
where('clients.raz_soc LIKE ?',"%#{params[:search_raz_soc]}%")

Related

Ruby on rails: Updating attribute on an association

In my controller I have the following:
def sort
params[:order].each do |key,value|
Question.find(value[:id]).update_attribute(:order,value[:order])
end
render :nothing => true
end
This works perfectly to update the order column for the 'Question' item.
However i've now moved the order column to a new table 'question_sections' which is associated to Questions.
class Question < ActiveRecord::Base
has_many :sections, :through => :question_sections
belongs_to :section
has_many :question_sections
default_scope { order(order: :asc) }
accepts_nested_attributes_for :section, :reject_if => :all_blank, allow_destroy: true
accepts_nested_attributes_for :question_sections, :reject_if => :all_blank, allow_destroy: true
end
I'm trying to adapt the sort function to update the 'order' column in 'question_sections' but am having trouble with it.
Any help on what the function should look like?
In case you are using nested attributes, you shoud call the includes method, and then iterate over each question_sections:
def sort
params[:order].each do |key,value|
questions = Question.includes(:question_sections).find(value[:id])
questions.question_sections.each { |q| q.update_attribute(:order,value[:order]) }
end
render :nothing => true
end
This breaks the problems into 2 parts, load all the question_sections needed:
1) Load all the question_sections of a question:
questions = Question.includes(:question_sections).find(value[:id])
Question Load
SELECT "questions".* FROM "questions" WHERE "questions"."id" = ? LIMIT 1 [["id", 1]]
QuestionSections Load
SELECT "question_sections".* FROM "question_sections" WHERE "question_sections"."question_id" IN (1)
2) update this question_sections
questions.question_sections.each { |q| q.update_attribute(:order,value[:order]) }
QuestionSections Update
UPDATE "question_sections" SET "order" = ?, "updated_at" = ? WHERE "question_sections"."id" = ? [["order", "different order now"], ["updated_at", "2017-03-09 13:24:42.452593"], ["id", 1]]
I think if you are using nested_attributes for Question model here then Rails should automatically update the nested params for QuestionSection
The controller should look something like this:
def sort
#question = Question.find_by(id: params[:id])
#question.update_attributes(question_params)
end
private
def question_params
params.require(:question).permit!
end
The parameters received to the controller should be like :
params = { question: {
abc: 'abc', question_sections_attributes: [
{ order_id: 1, ... },
{ order_id: 2, ... },
{ order_id: 3, ... }
]
}}
I hope this helps :)

Rails order by a field in parent belongs_to association

I have three models in my Rails app, User, Number, and Message:
class User < ActiveRecord::Base
has_many :numbers
has_many :messages, through: :numbers
end
class Number < ActiveRecord::Base
belongs_to :user
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :number
end
Number migration file has:
t.string :digits, index: true # Example: '14051234567' (no + sign)
In my controller:
sort_mode = # asc or desc
#messages = current_user.messages.order(???)
The thing is that I want to sort those messages by their numbers' digits.
How to do that dynamically (depending on sort_mode)?
EDIT:
sort_mode = 'asc'
#messages = current_user.messages.includes(:number)
order = { number: { digits: sort_mode } }
#messages = #messages.order(order)
^ Doesn't work. Second argument must be a direction.
Also, order('number.digits': sort_mode) throws:
SQLite3::SQLException: no such column: messages.number.digits: SELECT "messages".* FROM "messages" INNER JOIN "numbers" ON "messages"."number_id" = "numbers"."id" WHERE "numbers"."user_id" = ? ORDER BY "messages"."number.digits" ASC LIMIT 10 OFFSET 0
You'll need to use includes. Try:
#messages = current_user.messages.includes(:number).order('numbers.digits ASC')

SQLite3::SQLException: ambiguous column name: id: SELECT DISTINCT id FROM "tickets"

I really don't think the title of this explains well of what I'm trying to do but I'm not even sure how to ask.
So I have ticket has_many tasks and task belongs_to account. I've this as a scope to return the ticket listing where an tickets task belongs to an account:
scope :for_tasks_account, lambda { |account| joins(:tasks => :account ).where("accounts.id = ?", account.id) }
but it's returning multiple of the same ticket because a ticket has multiple tasks that the account belongs to.
How can I get it to only return each ticket once rather for each task in that ticket that an account belongs to?
Thanks!
Update
I'd actually like to combine to scopes to list all that apply to the two lambdas:
scope :for_account, lambda { |account| joins(:group => :accounts ).where("accounts.id = ?", account.id) } || lambda { |account| joins(:tasks => :account ).where("accounts.id = ?", account.id) }
Is this possible? As well as the first issue.
Update 2
I've figured out how to get both of the queries to be combined but I'm still getting multiple of the same ticket in the returned query.
scope :for_group_with_account, lambda { |account| joins(:group => :accounts ).where("accounts.id = ?", account.id) }
scope :for_task_with_account, lambda { |account| joins(:tasks => :account ).where("accounts.id = ?", account.id) }
scope :for_account, lambda { |account| for_group_with_account(account) & for_task_with_account(account).select('DISTINCT id') }
I'm using DISTICNT but I still get
SQLite3::SQLException: ambiguous column name: id: SELECT DISTINCT id FROM "tickets" INNER JOIN "groups" ON "groups"."id" = "tickets"."group_id" INNER JOIN "assignments" ON "groups"."id" = "assignments"."group_id" INNER JOIN "accounts" ON "accounts"."id" = "assignments"."account_id" INNER JOIN "tasks" ON "tasks"."ticket_id" = "tickets"."id" INNER JOIN "accounts" "accounts_tasks" ON "accounts_tasks"."id" = "tasks"."account_id" WHERE ("tickets"."archived" IS NULL) AND (accounts.id = 20) LIMIT 20 OFFSET 0
Thanks again!
I think you should be able to use "distinct" in this scenario.
scope :for_tasks_account, lambda { |account| joins(:tasks => :account ).where("accounts.id = ?", account.id).select('distinct accounts.id') }

Rails 3.1: Why do all the dealt cards end up attached to a single player?

I'm new to Rails, so I apologize for the title of the question, I didn't know how phrase it. Feel free to change it. I'm building a poker game to learn rails and I have the following associations...
class Game < ActiveRecord::Base
has_many :players, :dependent => :destroy
has_many :community_cards, :class_name => "Card", :dependent => :destroy, :conditions => { :is_community_card => true }
has_many :used_cards, :class_name => "Card", :dependent => :destroy, :conditions => { :is_community_card => false }
attr_accessible :pot, :name, :status
class Player < ActiveRecord::Base
belongs_to :game
has_many :cards, :dependent => :destroy
attr_accessible :chip_count, :position, :fb_id
end
class Card < ActiveRecord::Base
belongs_to :player
belongs_to :game
attr_accessible :face, :suit, :is_community_card
end
When I attempt to deal out random cards to all the players, all the cards end up with a single player...
def deal_players_hole_cards
players.all.each do |p|
if(p.cards.count < 2)
first_card = deal_card()
second_card = deal_card()
p.cards << first_card
p.cards << second_card
end
end
end
Here's the deal card method...
def deal_card
card_was_found = false
while(!card_was_found) do
card_was_found = true
random_suit = (0..3).to_a.sample
random_face = (1..13).to_a.sample
used_cards.all.each do |used_card|
if(random_suit == used_card.suit and random_face == used_card.face)
card_was_found = false
end
end
end
new_card = Card.create(:suit => random_suit, :face => random_face, :is_community_card => false)
used_cards << new_card
end
There are two players and each player should have two cards, but instead, one player has all four cards...
ruby-1.9.2-p290 :001 > Game.last.players.last.cards.count
Game Load (0.1ms) SELECT "games".* FROM "games" ORDER BY "games"."id" DESC LIMIT 1
Player Load (0.1ms) SELECT "players".* FROM "players" WHERE "players"."game_id" = 2 ORDER BY "players"."id" DESC LIMIT 1
(0.2ms) SELECT COUNT(*) FROM "cards" WHERE "cards"."player_id" = 6
=> 4
ruby-1.9.2-p290 :002 > Game.last.players.first.cards.count
Game Load (0.4ms) SELECT "games".* FROM "games" ORDER BY "games"."id" DESC LIMIT 1
Player Load (0.3ms) SELECT "players".* FROM "players" WHERE "players"."game_id" = 2 LIMIT 1
(0.2ms) SELECT COUNT(*) FROM "cards" WHERE "cards"."player_id" = 5
=> 0
Thanks so much in advance for all your wisdom!
I ended up fixing this by passing in the player object to the deal card method and attaching the newly created cards to the player by using the build method...
####################################################################
# Deals each player their two hole cards
####################################################################
def deal_players_hole_cards
players.all.each do |p|
if(p.cards.count < 2)
deal_card(p)
deal_card(p)
end
end
end
####################################################################
# returns a random, unused card
####################################################################
def deal_card(p)
card_was_found = false
while(!card_was_found) do
card_was_found = true
random_suit = (0..3).to_a.sample
random_face = (1..13).to_a.sample
used_cards.all.each do |used_card|
if(random_suit == used_card.suit and random_face == used_card.face)
card_was_found = false
end
end
end
new_card = p.cards.build(:suit => random_suit, :face => random_face, :is_community_card => false)
used_cards << new_card
end
Results...
ruby-1.9.2-p290 :005 > Game.last.players.first.cards.count
Game Load (0.3ms) SELECT "games".* FROM "games" ORDER BY "games"."id" DESC LIMIT 1
Player Load (0.4ms) SELECT "players".* FROM "players" WHERE "players"."game_id" = 2 LIMIT 1
(0.3ms) SELECT COUNT(*) FROM "cards" WHERE "cards"."player_id" = 5
=> 2
ruby-1.9.2-p290 :006 > Game.last.players.last.cards.count
Game Load (0.4ms) SELECT "games".* FROM "games" ORDER BY "games"."id" DESC LIMIT 1
Player Load (0.4ms) SELECT "players".* FROM "players" WHERE "players"."game_id" = 2 ORDER BY "players"."id" DESC LIMIT 1
(0.2ms) SELECT COUNT(*) FROM "cards" WHERE "cards"."player_id" = 6
=> 2
I'm still curious why my old code doesn't work.

How to use ActiveRecord's INCLUDES when looping over an Object

I have the following:
#rooms = current_user.rooms
Then I need to build a JSON object so I do:
render :json => room_json_index(#rooms)
Then to build the JSON object:
def room_json_index(rooms)
#roomList = Array.new
rooms.each do |room|
#roomList << {
:id => room.id,
:user_id => room.user_id,
:user_count => room_members.length,
:user_photos => room_members.collect { |room_member|
{
:id => room_member.user.id,
:photo => room_member.user.photo(:thumb),
:name => room_member.user.full_name
}
}
}
end
#roomList.to_json
end
Problem here is that in every loop of rooms.each, rails keeps hitting the data for the same user objects. Is that necessary. I see in the logs that it is caching but I'd rather rails not even have to thinking about it.
roomMember Load (1.1ms) SELECT "room_members".* FROM "room_members" INNER JOIN "users" ON "users"."id" = "room_members"."user_id" WHERE ("room_members".room_id = 143) AND (users.guest = false OR users.guest = true AND users.fname IS NOT NULL OR users.id = 3)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 69 LIMIT 1
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 70 LIMIT 1
Room
Rails in the logs is repeating the request above over and over, looking for the same records over and over. Any ideas on how this can be optimized?
Thanks
seems your data model is like
class User << AR::Base
has_many :room_members
has_many :rooms,:through=>:room_members,:include=>:users
......
end
class Room << AR::Base
has_many :room_members
has_many :users,:through=>:room_members
......
end
class RoomMember << AR::Base
belongs_to :room
belongs_to :user
......
end
you can load user when load room
class User << AR::Base
has_many :room_members
has_many :rooms,:through=>:room_members,:include=>:users
......
end

Resources