Let's say I have a table World.
I have a field called foo within the table. I want to query the World table and select foo, but I would like to alias it as bar in the subsequent conversion to JSON output.
Is there any way to alias the field name for just this one ActiveRecord query? Not looking to alias the field through the entire application.
Just use the SQL alias feature in a select method call:
w = World.select("foo as bar").first
w.bar # returns value for foo
w.foo # ActiveModel::MissingAttributeError
I avoid writing SQL as much as I can, so I would rather use ARel to build the query. Something like
World.select(World.arel_table['foo'].as('bar'))
Using some syntactic sugar, it's just:
at = World.arel_table
World.select(at['foo'].as('bar'))
You can override to_json method in yours World model. Check details on how to do that here How to override to_json in Rails?
Related
I had a bit more complex sql-query which i decided to use plain sql rather than writing it with AR. I wrapped the sql-statement inside ActiveRecord::Base.connection.exec_query` .
The method basically looks like that:
def sc_agent
return ActiveRecord::Base.connection.exec_query("SQL").as_json
end
The serializer as_json gives me a json hash with json strings. So also id's are now strings
{"id":"123","age":"99"}
On standard queries where i use AR i receive nicely
formatted json with the correct types.
How can i retain the correct types of all the values when using the ConnectionAdapter directly? Thanks for everything!
Use find_by_sql method.
Example: Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date].
More info is here: http://api.rubyonrails.org/classes/ActiveRecord/Querying.html
I have to use a query like this :
query = Enc.joins(:rec).group("enc.bottle").
select("enc.bottle as mode, count(rec.id) as numrec, sum(enc.value) as sumvalue")
That I use with :
#enc = ActiveRecord::Base.connection.select_all(query)
To get the data, I've to do #enc.rows.first[0] (it works)
But #enc.rows.first["mode"] doesn't work ! Because each row of #enc.rows contains array.. not a map with the name of each field.
Maybe select_all is a wrong method.
Does it exist another method to get the data with the name of field ?
Thank you
EDIT
If you can associate a model with the query, then there's no need for the generic select_all method. You can use find_by_sql like this:
Enc.find_by_sql(query).first.mode
# => testing
Note that you will no be able to see the aliases when inspecting the results, but they are there. Also, the convention is to use plural names for the tables. You might find it easier to just sticks with the defaults.
I have a simple active record query.
Product.active.select('stats_date, clicks_through')
I want to make clicks_through as a variable that will contain name of the attribute.
I tried
.select('stats_date, #{type_of_data}')
But this is not working. Any suggestions?
If type_of_data is a variable that holds a string or symbol that is a column in your database, the following should work (assuming that Product.active is a scope that returns an ActiveRecord::Relation).
Just change it to:
.select("stats_date, "#{type_of_data}")
(note the double quotes, which are required to use string interpolation in Ruby).
It's been almost 10 years, but there are some public methods available for this;
User.select(
User.sanitize_sql_array([':column', column: 'id'])
)
# "SELECT 'id' FROM \"users\"
It's basically that, you use the methods that ActiveRecord provides to sanitize the arguments for select.
Whether your query is prone to SQLi or not will depend entirely on the implementation of the sanitize_ methods.
I'm trying to update a field in using update_all. However I need the value to be taken from another field which is re-written to my specific format.
If I have something like this in my model:
def self.clean_mac_address()
clean_mac_address = :macaddress.gsub(/[^0-9a-z]/i, '')
end
When I run this:
Radacct.update_all("mac_clean = #{clean_mac_address}")
I get an error:
NoMethodError: undefined method `gsub' for :macaddress:Symbol
Any thoughts how I can do this? Or is there a simpler way to update the field?
update_all generates a single SQL query to run - it can't do clever stuff like change arbitrary bits of ruby into equivalent SQL.
You either need to load all you instances (via find_each for example) and fix them one by one (ie don't use update_all), for example
Foo.find_each do |foo|
# update foo here
foo.save!
end
Or find a way of expressing that cleaning operation in SQL. For example Postgres has a regexp_replace function
Foo.update_all("some_column = regexp_replace(some_column, 'your_regexp_here', '','g')")
Which would remove everything replacing that regexp. Obviously you'll need to check the documentation for your database to see whether it supports such a feature.
While the accepted answer provides a nice way to update_all, what I'd use is
read_with_clean_addr = Radacct.where(mac_clean: :macaddress.gsub(/[^0-9a-z]/i, ''))
read_with_clean_add.update_all(mac_clean: "#{clean_mac_address}")
I need to test if an instance variable in my controller contains a specific value. I think .include? would be the way to do it but that doesn't seem to work.
My code looks something like this:
#names=Model.find_by_sql("select name from ...")
if #names.include?(params[:name])
...
end
The if statement somehow allways evaluates to true.
Thanks
Firstly, find_by_sql is not a good way to do. find_by_sql will return you an object of class Model. Whereas params[:name] is most likely a string. The following should work:
Model.find(:all, :conditions => 'specify conditions here').map(&:name).include?(params[:name])
The results of find_by_sql will be (from the docs):
an array with columns requested encapsulated as attributes of the model you call this method from.
You need to search within the results.