Issue with raw SQL in Rails - sql

I use raw SQL to build an SQL editor in my project. But when I call simple select queries, I get this result:
[{"id"=>1, "name"=>"Ukraine", "phone_code"=>"+38", "created_at"=>"2015-11-23 21:52:49.415748", "updated_at"=>"2015-11-23 21:52:49.415748", 0=>1, 1=>"Ukraine", 2=>"+38", 3=>"2015-11-23 21:52:49.415748", 4=>"2015-11-23 21:52:49.415748"}]
The query is simple:
SELECT * FROM countries
As you can see, the same fields are displayed firstly with titles of attributes, and then second time with integer indexes.
I use this code two output only elements with attribute titles:
#headers = #result.first.keys
#count = #headers.size / 2
After that I iterate over headers:
<tr>
<% (0...#count).each do |i| %>
<th><%= #headers[i] %></th>
<% end %>
</tr>
But I think that it is not the best solution. So, what is the best way to output only elements with proper titles, not with indexes?

Try select_all
$ bin/rails c
Loading development environment (Rails 4.2.4)
>> result = ActiveRecord::Base.connection.select_all "SELECT * FROM wingnuts"
(0.4ms) SELECT * FROM wingnuts
=> #<ActiveRecord::Result:0x007fb92fbcdb18 #columns=["id", "size"], #rows=[[1, 10], [2, 11], [3, 12]], #hash_rows=nil, #column_types={}>
>> result.each { |row| puts row.inspect }
{"id"=>1, "size"=>10}
{"id"=>2, "size"=>11}
{"id"=>3, "size"=>12}
=> [{"id"=>1, "size"=>10}, {"id"=>2, "size"=>11}, {"id"=>3, "size"=>12}]

If you already have the known keys that you want to extract from the hash, then you can just use Hash#select method as following:
a = [{"id"=>1, "name"=>"Ukraine", "phone_code"=>"+38", "created_at"=>"2015-11-23 21:52:49.415748", "updated_at"=>"2015-11-23 21:52:49.415748", 0=>1, 1=>"Ukraine", 2=>"+38", 3=>"2015-11-23 21:52:49.415748", 4=>"2015-11-23 21:52:49.415748"}]
known_keys = %w(id name phone_code created_at updated_at)
a[0].select { |key, value| known_keys.include? key }
# => {"id"=>1, "name"=>"Ukraine", "phone_code"=>"+38", "created_at"=>"2015-11-23 21:52:49.415748", "updated_at"=>"2015-11-23 21:52:49.415748"}

I am not sure why you are returning in this manner, but in answer to your question "what is the best way to output only elements with proper titles, not with indexes?":
# The new, properly formatted object
hash_of_proper_keys = Hash.new
# Assuming country is in the form of a hash of values
country.each do |key, value|
hash_of_proper_keys[key] = value unless key.is_a? integer
end

Related

Variable variable in grails like in php

I am trying to achieve variable variable concept of PHP in grails, my code structure is somewhat similar to,
<%
def a = 6
def b = "a"
println "${"$b"}"
%>
I would like the output of
println "${"$b"}"
6, is it possible in any way?
the data is passed from the controller in some structure like [template:"something.gsp",model:["age":5,"date":"2011-01-01","id":9, listedKey:["age","date","id"]]] now when I iterate over the list listedKey I would like to get the value of its respective variable in view
Access the model map like this:
<g:each in=${listedKey} var="key">
${binding[key]}
</g:each>
You can do the following just straight in the gsp:
<g:set var="a" value="${6}"/>
<g:set var="b" value="a"/>
${a}
"${b}"
or
<%
def a = 6
def b = "a"
out << b
%>
${b} <- also working

including rails object in meta tags keywords

I'd like to include a rails object in my keywords as well as straight text but the code is clearly not the right way to do it...how can I do this?
set_meta_tags :keywords => %w[keyword1 keyword2 #{params[:hospital]}]
You might want to have a look at two plug-ins for including rails object in meta tags:
Meta Magic: https://github.com/lassebunk/metamagic
Head Liner: https://github.com/mokolabs/headliner
Edit: For Meta tag gem
What I usually do is write a meta helper that I simply stick in my ApplicationHelper, that looks like this:
def meta(field = nil, list = [])
field = field.to_s
#meta ||= {
'robots' => ['all'],
'copyright' => ['My Copyright'],
'content-language' => ['en'],
'title' => [],
'keywords' => []
}
if field.present?
#meta[field] ||= []
case list.class
when Array then
#meta[field] += list
when String then
#meta[field] += [list]
else
#meta[field] += [list]
end
case field
when 'description' then
content = truncate(strip_tags(h(#meta[field].join(', '))), :length => 255)
else
content = #meta[field].join(', ')
end
return raw(%(<meta #{att}="#{h(field)}" content="#{h(content)}"/>))
else
tags = ''
#meta.each do |field, list|
tags += meta(field)+"\n"
end
return tags.rstrip
end
end
You can simply set meta tags in your views, by adding a call to meta() in it. So in an articles/show.html.erb you might add this to the top of your view:
<% meta(:title, #article.title) %>
And in your layouts, you add it without any parameters, so it'll spit out the meta tags.
<%= meta %>
Or have it output an individual tag:
<%= meta(:title) %>
I bet you there's more elegant solutions, though.
But if you were looking for something already implemented in Rails you're out of luck.
Thanks.
Try this in your view as it worked for me (using meta-tags gem):
<% keywords [[#modelname.keyword1], [#modelname.keyword2]] %>
and you cad additional keywords in text format by adding them within the ruby in the following format ['keyword3']

rails OR query based on multiple checkbox selections

This seems like it should be a common problem but I'm having trouble finding an answer. Basically I want to have a form with 10 or so checkboxes which I'm creating with check_box_tag. When the form is submitted I want to generate a query that return all records that match ANY of the checked selections. So, the number of checked selections will vary.
So, for example, if I have
class Book < ActiveRecord::Base
belongs_to :author
end
I want to generate something like
Book.where("author_id = ? or author_id = ?", params[authors[0]], params[authors[1]]) if there are two boxes checked, etc.
Thanks for any insight.
Will this work for you?
Book.where(author_id: [array_of_author_ids])
You need to collect author_ids from params first
I recently had to do something similar, this is how I achieved this. It's pretty clever (at least I think so. :))
I created a query model that serializes the query column (text field) in JSON. I use a form to get the query data from the user with selection fields.
class BookQuery < ActiveRecord::Base
has_many :books
# loop through each foreign key of the Book table and create a hash with empty selection
def self.empty_query
q = {}
Book.column_names.each do |column_name|
next unless column_name.ends_with?("_id")
q.merge column_name => []
end
end
end
I'm using Author as an example below:
<%= form_for #book_query do |f| %>
<% for author in Author.all %>
<%= check_box_tag "book_query[query][author_ids][]", author.id, false%>
<%= author.name %>
<% end %>
<%= f.submit "Save Query" %>
<% end %>
When this form is submitted you ended up with parameters like this:
When the form is submitted it generates this parameter:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXXXXXXXXXX", "book_query"=>{"query"=>{"author_ids"=>["2", "3"]}}, "commit"=>"Save Query"}
Now in the BookQuery controller's create action you can just do what create function always does:
def create
#book_query = BookQuery.build(params[:book_query])
if #book_query.save
flash[:success] = "Book query successfully saved."
redirect_to ...
else
flash[:error] = "Failed to save book query."
render :new
end
end
But by default rails serializes the data in hash type:
1.9.3p194 :015 > pp BookQuery.find(9).query
BookQuery Load (0.7ms) SELECT "book_queries".* FROM "book_queries" WHERE "book_queries"."id" = $1 LIMIT 1 [["id", 9]]
"--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nauthor_ids:\n- '2'\n- '3'\n"
=> "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nauthor_ids:\n- '2'\n- '3'\n"
In BookQuery model, add the following:
serialize :query, JSON
But rail would change the IDs to string:
1.9.3p194 :018 > query = JSON.parse(BookQuery.find(10).query)
BookQuery Load (0.5ms) SELECT "book_queries".* FROM "book_queries" WHERE "book_queries"."id" = $1 LIMIT 1 [["id", 10]]
=> {"author_ids"=>["2", "3"]}
1.9.3p194 :019 > query["author_ids"]
=> ["2", "3"]
What I did then is override the attribute accessors in BookQuery model:
The below has to be done because the hash returns strings, not ids in integer.
def query=(query)
query.each_pair do |k, v|
if query[k].first.present?
query[k].map!(&:to_i)
else
query.except!(k)
end
end
write_attribute(:query, query)
end
# just want to avoid getting nil query's
def query
read_attribute(:query) || {}
end
To find book with this query, you can simply add this function to your Book model:
def self.find_by_book_query(book_query, options = {})
options[:conditions] = book_query.query
find(:all, options)
end
Now you get a customizable query string based on the model definition Book and everything works like the Rails way. :)

Access a query in Ruby on Rails

I have in my controller this:
#itemsok = Search.where("first_item_id = ?", params["3"])
This is sopposed to be a query in the search table of the database asking for all the searches that have a first_item_id = 3 ...
Question 1 .- The syntax is I found it in http://guides.rubyonrails.org/active_record_querying.html but im not sure if im using it right?
Ok the question 2 is, I have this on the controller, is it ok to have querys in the controller?
In the view im printing the variable <%= #itemsok %> and all I get is a
ActiveRecord::Relation:0x007fd3d3e894d8
Any suggestions?
Thanks in advance.
ActiveRecord 3 lets you chain relations together so you can do something like this:
#itemsok = Search.where("first_item_id = ?", params["3"]).where("foo = ?", "bar")
The where() function returns an ActiveRecord::Relation. Generally this isn't a problem, since if you use the object it'll automatically run the query and return the results on the object so you'll get the database objects. AR doesn't run the query until it's actually needed.
Where will return a list of items (Array), so if you're just debugging, change your view to this:
<%= debug #itemsok.to_a %>
You seem to be constructing the query wrong way.
If you want to search for records with first_item_id = 3, you should do:
Search.where("first_item_id = ?", 3)
This will return an array of matching records, something you can't easily print with <%= #itemsok %>. You should iterate over the elements and print each one:
<% #itemsok.each do |item| %>
<%= item.name %>
<% end %>
I'd also suggest defining to_s method for the objects you want to print.
class Search
def to_s
name
end
end
Then you can simply print the object and to_s method will be automatically called for you:
<% #itemsok.each do |item| %>
<%= item %>
<% end %>
The right way to do is to define a namedscope in the model and then use it in the controller.
Something similar to this :
class Search < ActiveRecord::Base
named_scope:item_ok,lambda {|*args|{:conditions=>["item_id >= ?", args.first]}}
end
and then call the namedscope from the controller like this :
#itemsok = Search.item_ok(params[:value])

How to render all records from a nested set into a real html tree

I'm using the awesome_nested_set plugin in my Rails project. I have two models that look like this (simplified):
class Customer < ActiveRecord::Base
has_many :categories
end
class Category < ActiveRecord::Base
belongs_to :customer
# Columns in the categories table: lft, rgt and parent_id
acts_as_nested_set :scope => :customer_id
validates_presence_of :name
# Further validations...
end
The tree in the database is constructed as expected. All the values of parent_id, lft and rgt are correct. The tree has multiple root nodes (which is of course allowed in awesome_nested_set).
Now, I want to render all categories of a given customer in a correctly sorted tree like structure: for example nested <ul> tags. This wouldn't be too difficult but I need it to be efficient (the less sql queries the better).
Update: Figured out that it is possible to calculate the number of children for any given Node in the tree without further SQL queries: number_of_children = (node.rgt - node.lft - 1)/2. This doesn't solve the problem but it may prove to be helpful.
It would be nice if nested sets had better features out of the box wouldn't it.
The trick as you have discovered is to build the tree from a flat set:
start with a set of all node sorted by lft
the first node is a root add it as the root of the tree move to next node
if it is a child of the previous node (lft between prev.lft and prev.rht) add a child to the tree and move forward one node
otherwise move up the tree one level and repeat test
see below:
def tree_from_set(set) #set must be in order
buf = START_TAG(set[0])
stack = []
stack.push set[0]
set[1..-1].each do |node|
if stack.last.lft < node.lft < stack.last.rgt
if node.leaf? #(node.rgt - node.lft == 1)
buf << NODE_TAG(node)
else
buf << START_TAG(node)
stack.push(node)
end
else#
buf << END_TAG
stack.pop
retry
end
end
buf <<END_TAG
end
def START_TAG(node) #for example
"<li><p>#{node.name}</p><ul>"
end
def NODE_TAG(node)
"<li><p>#{node.name}</p></li>"
end
def END_TAG
"</li></ul>"
end
I answered a similar question for php recently (nested set == modified preorder tree traversal model).
The basic concept is to get the nodes already ordered and with a depth indicator by means of one SQL query. From there it's just a question of rendering the output via loop or recursion, so it should be easy to convert this to ruby.
I'm not familiar with the awesome_nested_set plug in, but it might already contain an option to get the depth annotated, ordered result, as it is a pretty standard operation/need when dealing with nested sets.
Since september 2009 awesome nested set includes a special method to do this:
https://github.com/collectiveidea/awesome_nested_set/commit/9fcaaff3d6b351b11c4b40dc1f3e37f33d0a8cbe
This method is much more efficent than calling level because it doesn't require any additional database queries.
Example: Category.each_with_level(Category.root.self_and_descendants) do |o, level|
You have to recursively render a partial that will call itself. Something like this:
# customers/show.html.erb
<p>Name: <%= #customer.name %></p>
<h3>Categories</h3>
<ul>
<%= render :partial => #customer.categories %>
</ul>
# categories/_category.html.erb
<li>
<%= link_to category.name, category %>
<ul>
<%= render :partial => category.children %>
</ul>
</li>
This is Rails 2.3 code. You'll have to call the routes and name the partial explicitely before that.
_tree.html.eb
#set = Category.root.self_and_descendants
<%= render :partial => 'item', :object => #set[0] %>
_item.html.erb
<% #set.shift %>
<li><%= item.name %>
<% unless item.leaf? %>
<ul>
<%= render :partial => 'item', :collection => #set.select{|i| i.parent_id == item.id} %>
</ul>
<% end %>
</li>
You can also sort their:
<%= render :partial => 'item', :collection => #set.select{|i| i.parent_id == item.id}.sort_by(&:name) %>
but in that case you should REMOVE this line:
<% #set.shift %>
Maybe a bit late but I'd like to share my solution for awesome_nested_set based on closure_tree gem nested hash_tree method:
def build_hash_tree(tree_scope)
tree = ActiveSupport::OrderedHash.new
id_to_hash = {}
tree_scope.each do |ea|
h = id_to_hash[ea.id] = ActiveSupport::OrderedHash.new
(id_to_hash[ea.parent_id] || tree)[ea] = h
end
tree
end
This will work with any scope ordered by lft
Than use helper to render it:
def render_hash_tree(tree)
content_tag :ul do
tree.each_pair do |node, children|
content = node.name
content += render_hash_tree(children) if children.any?
concat content_tag(:li, content.html_safe)
end
end
end
I couldn't get to work the accepted answer because of old version of ruby it was written for, I suppose. Here is the solution working for me:
def tree_from_set(set)
buf = ''
depth = -1
set.each do |node|
if node.depth > depth
buf << "<ul><li>#{node.title}"
else
buf << "</li></ul>" * (depth - node.depth)
buf << "</li><li>#{node.title}"
end
depth = node.depth
end
buf << "</li></ul>" * (depth + 1)
buf.html_safe
end
It's simplified by using the optional depth information.
(Advantage of this approach is that there is no need for the input set to be the whole structure to the leaves.)
More complex solution without depths can be found on github wiki of the gem:
https://github.com/collectiveidea/awesome_nested_set/wiki/How-to-generate-nested-unordered-list-tags-with-one-DB-hit