Null vs Nil in database - sql

I am using an SQLite3 database with my rails app and am having a very frustrating time trying to solve this problem.
I want to populate check boxes in a different manner depending on if the form (_form.html.erb) is being rendered in update or in create so:
<% if #foo.new_record? %>
<% query = "association_id == nil" %>
<% else %>
<% query = "" %>
<% end %>
and then I pass the query string to my check boxes
collection_check_boxes(:host, :association_ids, Association.where(query), :id, :name)
What this should do is give me all of the associations as check boxes for update and only ones that don't already have an association_id when creating.
If I replace the query with :association_id=>nil I will get the desired result for create.
If I replace the query with Association.all, I get the result for update.
I could just replicate all of my code manually in the check for new_record? but my code is already rather long and complicated and that would make it doubly so. So I wanted to just pass a string (query) to my where call. This is where I ran into trouble.
When I look in the rails console and make direct SQL queries I notice that returned files without an association_id will show up as association_id: nil. So I try to match to nil but that gives me an "unknown column: nil" error from SQL. When I try to match to the SQL NULL it doesn't find anything.
How is a nil attribute stored in the database and how do I query to find it using a string?

You should do
<% query = "association_id is null" %>
Association.where(:association_id => nil)
will be converted internally into a query like below
select * from associations where association_id is null

Related

ActiveRecord Joins

Ok, so, if I do a User.joins(:session_users), I only get the attributes of users table.
How do I get the attributes of both tables in ActiveRecord way, i.e., not SQL?
EDIT ONE
Ok, based on the first answer, I'm trying to have it displayed.
So, this is the method written in Users Controller
def blah
#users = User.includes(:session_users)
#users.each do |user|
user.session_users
end
end
Then I have this in the users view blah.html.erb
<%= #users.session_users %>
And this in the routing section:
match "/users/blah" => "users#blah"
I think you want includes instead of joins. See http://railscasts.com/episodes/181-include-vs-joins for more info. This should fetch columns for both,
users = User.includes(:session_users)
users.each do |user|
user.session_users
end
Note, this still performs 2 SQL queries.
Edit
Updated answer assumes that a user has_many :session_users
Routes:
# config/routes.rb
get '/users/blah' => 'users#blah'
Controller:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def blah
#users = User.includes(:session_users)
end
end
View:
# app/views/users/blah.html.erb
<% #users.each do |user| %>
<%= user.name %> // assumes user has a name attribute
<% user.session_users.each do |session_user| %>
<%= session_user.attributes %> // prints all the attributes
<%= session_user.created_at %> // assumes the user has a created_at attribute
<% end %>
<% end %>
If you really need to add fields from a joined table to the yielded objects, you can add select:
User.joins("INNER JOIN stolen_passwords
ON users.social_security_number=stolen_passwords.ssn")
.select("*").find_each do |user|
logger.debug {
"A #{user.full_name} has a password hash #{user.password_hash}"
}
end
Here imaginary user.full_name is an instance method of User and user.password_hash comes from the stolen_passwords table. You could also limit the queried/returned fields by listing them in the call to select explicitly.
We sometimes use this in rake tasks that enrich the database from or compare it against third party data sources: we would join our tables with provided tables and generate a 'side-by-side' CSV with columns from both. Plain SQL would work just as well, but going via active record often allows to reuse familiar scopes, or methods that perform calculations in ruby.
Caveat
Unfortunately the fields coming from the joined tables will not be cast to appropriate ruby types, they will all be strings (which is especially logical if using SQL string for the joins). But it is easy to cast the joined attributes with something like:
module CastJoinedColumns
def cast_joined_columns joined_record
columns_hash.each do |column_name, column|
if joined_record.attributes.include?(column_name)
joined_record[column_name] = column.type_cast(joined_record[column_name])
end
end
end
end
This module is meant to be extended into a model appearing on the right side of the join and the method be called with a joined record. It might misbehave and should be improved for the cases where the same column name appears in multiple tables, but is an ok starting point (works perfectly for us with third party data sources using column names guaranteed not to clash with our own).

Does MongoID do a separate query for .count(true)?

I have a ruby on rails 3 project in which I query for a certain number of objects by using a .limit(3) . Then, in my view, I loop through these objects. After that, if there are 3 objects in the view, I display a "load more" button. Here is the view code:
<% #objects.each do |object| %>
<%= render object._type.pluralize.underscore + '/teaser', :object => object %>
<% end %>
<% if #objects.size(true) == 3 %>
#load more link here
<% end %>
The size(true) is passed a boolean to ensure that mongoID takes into account the .limit and .offset on my query (otherwise it returns the total number of objects that matched, regardless of the limit / offset). Here are the relevant development log lines:
MONGODB project_development['system.indexes'].insert([{:name=>"_public_id_1", :ns=>"project_development.objects", :key=>{"_public_id"=>1}, :unique=>true}])
MONGODB project_development['objects'].find({:deleted_at=>{"$exists"=>false}}).limit(3).sort([[:created_at, :desc]])
#some rendering of views
MONGODB project_development['system.indexes'].insert([{:name=>"_public_id_1", :ns=>"project_development.objects", :key=>{"_public_id"=>1}, :unique=>true}])
MONGODB project_development['$cmd'].find({"count"=>"objects", "query"=>{:deleted_at=>{"$exists"=>false}}, "limit"=>3, "fields"=>nil})
My question is: does MongoID do a separate query for my #objects.size(true)? I imagine the ['$cmd'] might indicate otherwise, but I'm not sure.
I don't think so, there was a pull request month ago to add aliases for :size, :length to :count to avoid re-running queries. You can check that.

RoR, Passing a variable into view gives a null object

I am setting a variable in my controller but for some reason it is not getting set. I tried it two ways.
def update
# #available_cars = Car_info.where("user_id = ?", session[:user_id])
#available_cars = Car_info.find_by_user_id(session[:user_id])
end
In my view I do this.
<% #available_cars.each do |car| %>
<%= car.name %>
<% end %>
What I intend to do is populate the #available_cars into a drop down list but I can't even get them to print. I know the session[:user_id] is set because I print it and access it elsewhere.
I get this error...
Expected D:/RailsProjects/mileage/app/models/car_info.rb to define Car_info
in my controller
app/controllers/active_car_controller.rb:6:in `update'
Any help would be appreciated. New to RoR.
I see your controller method is named 'udpate' instead of 'update' - could that be your problem?
You need to change your query to:
#available_cars = Car_info.find_all_by_user_id(session[:user_id])
The find_all part will get you all records, whereas find only gets you the first. Another way to write this is:
#available_cars = Car_info.where("user_id = ?", session[:user_id])
Ideally, you want your class to be called CarInfo, not Car_info.

Rails 3 - how to work with data got from database

I am loading from database the only row. The data are stored in variable (e.g.) #data.
In view, if I want to display the value got from database, I have to do following:
<% #data.each do |d| %>
<%=d.name %>
<%end%>
And I would like to ask you - exist any better way? I think it's a bit silly for the only row to use loop... I tried something like
<%= #data.name %>
OR
<%= #data.each.name %>
But in both cases I got the error message about bad syntax...
So to my question - is possible to get display data a bit more elegantly?
EDIT: my query: #data = Car.includes(:tyres).where("param1 = ?", params[:param1])
If you've loaded more than one model (row), then a loop is the natural construct for displaying each value. If you're really set on a one-liner, you could use some of Ruby's list comprehensions:
<%= #data.map(&:name).join(" ") -%>
I think that you are loading .all instead of .first.
In your controller,
#data = Data.where(:some => 'condition').first
or
#data = Data.find(params[:id])

Running a SQL query in rails

I have a rails application where I have to subtract 2 time stamps and display the result on the webpage
I have used the following sql statement and I am getting the results.
select (julianday(resolutions.created_at)-julianday(tickets.created_at))*24 from tickets,resolutions
the value of tickets.created_at is 2010-04-05 18:59:02 which is a time stamp and value of resolutions.created_at is 2010-04-08 08:10:33
Now where do I put this sql so that I can be seen in my webpage.
I tried it in the views page with the following but nothing showed up:
<% #sql = "select (julianday(resolutions.created_at)-julianday(tickets.created_at))*24 from tickets,resolutions" %>
<% #t=(ActiveRecord::Base.connection.execute(#sql)) %>
So how do I display it on my webpage?
when I perform the above I get the output printed on the webpage as
061.1919444389641(julianday(resolutions.created_at)-julianday(tickets.created_at))*2461.1919444389641
only 61.1919444389641 is supposed to be printed but the query statement is also getting printed.
You should put your custom SQL in your model class, definitely not in the view.
In your controller
#tickets = Tickets.find(
:all,
:joins => :resolution,
:select => '(julianday(resolutions.created_at)-julianday(tickets.created_at))*24 AS interval'
)
In your view
<% #tickets.each do |ticket|%>
<%= ticket.interval %>
<% end %>
Generally you would put this logic in one of your models though, like this:
In your Tickets Model
def time_to_resolve
resolution.created_at - created_at
end
To reduce the number of queries when iterating over multiple queries you would use this:
Tickets.find(:all, :include => :resolution)