Increment counter and rails "first" using postgreSQL strange behavior [duplicate] - ruby-on-rails

This question already has answers here:
ActiveRecord Find All not sorting by ID?
(5 answers)
Closed 8 years ago.
When I increment some integer column using increment_counter and passing some record id and then try to get the first record using Model.first, this return the record id plus 1.
Something like this:
Model.increment_counter :field, id
Model.first
It returns not the
Model.find(1)
but
Model.find(id+1)
Is that some particular issue of postgreSQL?

Model.first will use the default sorting of your database (which is not necessarily an id).
Try this instead:
Model.order("id").first

You can do some monkey patching to ActiveRecord,
#lib/postgresql_extras.rb
module ActiveRecord
class Base
def self.first_by_id
order(:id).first
end
def self.all_by_id
order(:id)
end
end
end
and require this in some initializer
#config/initializer/extensions.rb
require "postgresql_extras"
don't call this ones first and all cause it will generate errors on other querys, for example User.order(:email).limit(1) it will be different from User.order(:email).first in this case, cause it will reorder by id the items,
I didn't find other methods with problems in posgresql yet and i try to fix it by change the tables pkey, but not luck there

Related

Delete from database with specific details in ruby

I try to delete from database all row has a id include in some array or (key,value)
"recp" => "1, 2, 3 , 6, 7 , ........."
ID in #recipient
I try this:
#v = NameOfDatabase.where.not(:id=> #recipient.split(',').map(&:to_i), :conditions => {:thread =>#dis_PI.m_id}).destroy_all
With specific condition i want to remove row with this condition and not include in #recipient
Error in this method :
NoMethodError (undefined method `where' for #<Class:0x7f447f57b140>):
I try multiple code but not working, i put this question multiple time but also not work yet!
From the comments, I learned that you are running a very old version of Ruby on Rails – probably more than 10 years old. With Rails 3.0 the finder methods change completely and therefore all current documentation for Rails will not be helpful anymore. Especially the where method did not exist before Rails 3.0
In such an old version the following should work:
YourModel.destroy_all("id in (?)", #recipient.split(','))
Here you will find the docs of older Rails versions.
The condition is basically just one SQL fragment. When you want to add more conditions then you need to write all conditions in one line like this:
YourModel.destroy_all(
"id IN (?) AND thread = ?", #recipient.split(','), #dis_PI.m_id
)

Remove element from ActiveRecord_Relation in rails

How can i remove the last element from an ActiveRecord_Relation in rails?
e.g. if I set:
#drivers = Driver.all
I can add a another Driver object called #new_driver to #drivers by doing:
#drivers << #new_driver
But how can I remove an object from #drivers?
The delete method doesn't seem to work, i.e.
#drivers.delete(0)
You can use the reject! method, this will remove the object from the collection without affecting the db
for example:
driver_to_delete = #driver.first # you need the object that you want removed
#drivers.reject!{|driver| driver == driver_to_delete}
Very late too, but I arrived here looking for a fast answer and finished by thinking by myself ;)
Just to clarify about the different answers and the Rails 6.1 comment on accepted answer:
The OP wanted to remove one entry from a query, but NOT remove it from database, so any answer with delete or destroy is just wrong (this WILL delete data from your database !!).
In Ruby (and therefore Rails) convention, shebang methods (ending with !) tend to alter the given parameter. So reject! would imply modifying the source list ... but an ActiveRecord_Relation is basically just a query, NOT an array of entries !
So you'd have 2 options:
Write your query differently to specifically say you don't want some id:
#drivers.where.not(id: #driver_to_remove) # This still is an ActiveRecord_Relation
Use reject (NO shebang) on your query to transform it into an Array and "manually" remove the entry you don't want:
#drivers.reject{ |driver| driver == #driver_to_remove}
# The `reject` forces the execution of the query in DB and returns an Array)
On a performance point of view, I would personally recommend the first solution as it would be just a little more complex against the DB where the latter implies looping on the whole (eventually large) array.
Late to the question, but just had the same issue and hope this helps someone else.
reject!did not work for ActiveRecord_Relation in Rails 4.2
drop(1) was the solution
In this case #drivers.drop(0) would work to drop the first element of the relation
Since its an array of objects, have you tried to write something like #drivers.delete(#new_driver) or #drivers.delete(id: #new_driver.id) ?
This is the documentation you need:
#group.avatars << Avatar.new
#group.avatars.delete(#group.avatars.last)
--
.destroy
The problem you've got is you're trying to use collection methods on a non-collection object. You'll need to use the .destroy ActiveRecord method to get rid of the record from the database (and consequently the collection):
#drivers = Driver.all
#drivers.last.destroy
--
Scope
.delete will remove the record from the DB
If you want to pull specific elements from the db to populate the #drivers object, you'll need to use a scope:
#app/models/driver.rb
Class Driver < ActiveRecord::Base
scope :your_scope, -> { where column: "value" }
end
This will allow you to call:
#app/controllers/drivers_controller.rb
def index
#drivers = Driver.your_scope
end
I think you're getting the MVC programming pattern confused - data manipulation is meant to happen in the model, not the controller
As stated above, reject! doesn't work in Rails 4.2, but delete does, so #drivers.delete(#new_driver) works, and more generally:
#drivers.delete(Driver.where(your condition))

Using Rails update_all method to update fields with value from another column

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}")

set_table_name only works once?

I'm trying to use set_table_name to use one generic model on a couple different tables. However, it seems as though set_table name only works on the class once per application session. For instance in a rails 3 console (ruby 1.8.7) the following happens:
GenericModel.set_table_name "table_a"
puts GenericModel.table_name # prints table_a
pp GenericModel.column_names # prints the columns associated with table_a
GenericModel.set_table_name "table_b"
puts GenericModel.table_name # prints table_b
pp GenericModel.column_names # still prints the columns associated with table_a
Currently the workaround I've found is to also add .from(table_b) so that queries don't error out with 'table_b.id doesn't exist!' because the query still thinks it's FROM table_a.
Can others reproduce the issue? Is this the intended behaviour of set_table_name?
UPDATE
Adding
Model.reset_column_information
after set_table_name forces the model to work as I expect.
Reference found in http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000368
This is probably an undocumented limitation. Once the SHOW FIELDS FROM has been executed, which is where the results from column_names comes from, it is usually cached, at least for the duration of the request. If you must, try using the console reload! method to reset things.
your choice
rename_table
more info at AR TableDefinition

Why "Object#id will be deprecated; use Object#object_id" when accessing AR record ID? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Rails primary key and object id
I am baffled as to why I cannot refer an object's attributes; hope someone can help...
I need to build a hash that will associate Marker.marker_name with it's id from the database, which are already stored (the record id will serve as a foreign key in another table).
So, first I retrieve the Marker record via this named scope:
class Marker < ActiveRecord::Base
named_scope :by_name, lambda { |marker_name|
{:conditions => ["marker_name = ?", marker_name]}}
which is called from my Uploads model, like this (marker_name has the value "Amelogenin"):
this_marker = Marker.by_name(marker_name)
I know this worked, because when I Use the debugger, I can see what is in this_marker, which looks like:
(rdb:2) y this_marker
!ruby/object:Marker attributes:
created_at: 2011-03-14 22:21:27.244885
updated_at: 2011-03-14 22:21:27.244885
id: "11"
marker_name: Amelogenin attributes_cache: {}
Yet, I cannot assign the record id in my hash, like this:
$markers[marker_name] = this_marker.id
I cannot seem to refer directly to the id in this way; because, even in the debugger, I get this error:
(rdb:2) p this_marker.id
(__DELEGATION__):2: warning: Object#id will be deprecated; use Object#object_id
Is there some kind of different Ruby syntax I need to be using or what? How can I associate the marker_name with its record id?
Thanks in advance....
This Marker.by_name(marker_name) returns an array of makers. You should write:
this_marker = Marker.by_name(marker_name).first
This kind of error happens when one calls id method on non ActiveRecord object. So make sure this_marker is AR object instance.
this_marker = Marker.by_name(marker_name) are you sure this returns one Marker object? There is no call to all or first.
That is a very confusing error message, (and I bet it's a fairly common problem too).
Marker.by_name(marker_name) does not return an active record object, but a scope, which does not have an active record id, only the Object#id method, which is deprecated (and gone in Ruby 1.9.2).
Scopes are lazy - they won't access the database until you try to use them (or print them, as in your case).
Try Marker.by_name(marker_name).first

Resources