I am trying to save changes to my database trough a rake task.
In my rake task I do something like:
namespace :parts do
desc "Update Parts table, swap names in title"
task :swap => :environment do
Part.swap
end
end
In my Part class I do
def self.swap
Part.all.each do |part|
if (part.title =~ REGEX) == 0
part.title.gsub! REGEX, '\2 \1'
puts part.title
part.save!
end
end
end
However, this does not save the part. The save! does return true. the puts part.title does return the value I want.
If I call
Part.update(part.id, title: part.title)
The database updates properly. Why is this? Am I doing something wrong in my loop?
I am working with Rails 3.1.3, Rake 0.9.2.2 and MySQL2 0.3.7
It's because the way ActiveRecord detects that attributes are changed is through the setter. Therefore, if you use gsub! on an attribute, ActiveRecord doesn't know it needs to update the database.
You'll probably have to do this:
part.title = part.title.gsub REGEX, '\2 \1'
Update from comment
Also, if you try to assign title to another variable and then gsub! it won't work either because it's the same object (code from my project, variable names different).
ruby-1.9.3-p0 :020 > t = p.name
=> "test"
ruby-1.9.3-p0 :023 > t.object_id
=> 70197586207500
ruby-1.9.3-p0 :024 > p.name.object_id
=> 70197586207500
ruby-1.9.3-p0 :025 > t.gsub! /test/, 'not a test'
=> "not a test"
ruby-1.9.3-p0 :037 > p.name = t
=> "not a test"
ruby-1.9.3-p0 :026 > p.save
(37.9ms) BEGIN
** NO CHANGES HERE **
(23.9ms) COMMIT
=> true
You have to .dup the string before modifying it.
ruby-1.9.3-p0 :043 > t = p.name.dup
=> "test"
ruby-1.9.3-p0 :044 > t.gsub! /test/, 'not a test'
=> "not a test"
ruby-1.9.3-p0 :045 > p.name = t
=> "not a test"
ruby-1.9.3-p0 :046 > p.save
(21.5ms) BEGIN
(20.8ms) UPDATE "projects" SET "name" = 'not a test', "updated_at" = '2012-01-02 07:17:22.892032' WHERE "projects"."id" = 108
(21.5ms) COMMIT
=> true
Related
I'm using ruby 2.2.3 and rails 4.2.4.
Background: I need the ability to re-use values across enums within the same model so I have patched in the latest version of Active Record's enum.rb as config/initializers/enum_patch.rb since they are adding prefix/suffix support in Rails 5 which will enable this functionality.
Issue: After patching in the code, Enum is no longer working correctly. See below:
class GatheringSession < ActiveRecord::Base
GatheringStates = %i(ready running finished errored)
enum :gathering_state => GatheringStates
...
end
Console (no patch). Correct behaviour:
2.2.3 :001 > gs2 = GatheringSession.last
=> #<GatheringSession id: 120, gathering_state: 2 ... >
2.2.3 :002 > gs2.gathering_state
=> "finished"
2.2.3 :003 > gs2.ready?
=> false
2.2.3 :004 > gs2.finished?
=> true
2.2.3 :005 > gs2.ready!
=> true
2.2.3 :007 > gs2.ready?
=> true
2.2.3 :008 > gs2.finished?
=> false
2.2.3 :009 > gs2.finished!
=> true
2.2.3 :010 > gs2.finished?
=> true
Console (patch):
2.2.3 :001 > gs2 = GatheringSession.last
=> #<GatheringSession id: 120, gathering_state: 2 ... >
2.2.3 :002 > gs2.gathering_state
=> 2
2.2.3 :003 > gs2.ready?
=> false
2.2.3 :004 > gs2.finished?
=> false
2.2.3 :005 > gs2.ready!
(0.2ms) BEGIN
SQL (0.8ms) UPDATE `gathering_sessions` SET `gathering_state` = 'ready', `updated_at` = '2015-10-31 00:28:36' WHERE `gathering_sessions`.`id` = 120
Mysql2::Error: Incorrect integer value: 'ready' for column 'gathering_state' at row 1: UPDATE `gathering_sessions` SET `gathering_state` = 'ready', `updated_at` = '2015-10-31 00:28:36' WHERE `gathering_sessions`.`id` = 120
(0.1ms) ROLLBACK
ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect integer value: 'ready' for column 'gathering_state' at row 1: UPDATE `gathering_sessions` SET `gathering_state` = 'ready', `updated_at` = '2015-10-31 00:28:36' WHERE `gathering_sessions`.`id` = 120
...
from /Users/william/.rvm/gems/ruby-2.2.3/gems/activerecord-4.2.4/lib/active_record/persistence.rb:263:in `update!'
from /Users/william/code/repo/config/initializers/enum_patch.rb:193:in `block (4 levels) in enum'
After doing a little bit of testing, I've realized the problem is not the new code that I've patched in, but the fact that I'm patching in code period. Even when using the same code that is shipped with Rails 4.2.4 (here) I get the same (incorrect) behaviour.
Does anyone have an idea why this is happening and how I can fix it?
#!/usr/bin/ruby
puts "Please enter the path-name of the directory:"
p = STDIN.gets
isdir = File.directory?(p)
puts "#{isdir} #{p}"
it always return me a false! even though I know the user input is a directory. I think (p) is not working as a parameter. So i think its saying that p is not a directory not the user input for example "/usr/bin/". any help?
Using p = STDIN.gets '\n' was getting appended. Instead you can use gets.chomp. Also you need to use File.expand_path. Check the example below.
# My irb
1.9.3-p545 :002 > p = gets.chomp
~/.ssh
=> "~/.ssh"
1.9.3-p545 :003 > File.directory?(p)
=> false
1.9.3-p545 :004 > File.exists? File.expand_path(p)
=> true
The p value is not strictly equal to what you expect it to be. It contains \n at the end:
# in my irb:
1.9.3p392 :010 > p = STDIN.gets
/home/
=> "/home/\n"
1.9.3p392 :011 > isdir = File.directory?(p)
=> false
1.9.3p392 :012 > isdir = File.directory?(p.strip)
=> true
The strip method:
Strips entire range of Unicode whitespace from the right and left of the string.
Source: http://apidock.com/rails/ActiveSupport/Multibyte/Chars/strip
I have a model that looks like this:
class WorkRequest < ActiveRecord::Base
attr_accessible :upload, :assigned_to_staff
serialize :assigned_to_staff, Array
before_save :set_old_staff
def set_old_staff
#old_staff = self.assigned_to_staff_was
end
def staff_changed?
!self.assigned_to_staff.empty? && self.assigned_to_staff != #old_staff
end
end
I'm trying to make use of self.assigned_to_was to track when a staff assignment change takes place. I'm noticing that the serialized field behaves differently than a regular field. Console output below shows differing behavior in :upload (text string field) and the serialized :assigned_to_staff:
1.9.2-p320 :002 > wr.upload
=> nil
1.9.2-p320 :003 > wr.upload_was
=> nil
1.9.2-p320 :004 > wr.upload = "Yes"
=> "Yes"
1.9.2-p320 :005 > wr.upload_was
=> nil
compared to:
1.9.2-p320 :006 > wr.assigned_to_staff
=> []
1.9.2-p320 :007 > wr.assigned_to_staff_was
=> []
1.9.2-p320 :008 > wr.assigned_to_staff << User.last.name
User Load (0.2ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
=> ["last5, first5"]
1.9.2-p320 :009 > wr.assigned_to_staff_was
=> ["last5, first5"]
Can anyone explain this discrepancy and or suggest a workaround?
It appears that serialization doesn't fully implement all methods of the host class. Overrides are provided for getters and setters, but not concatenation.
i use acts-as-taggable-on for tagging.
apartments_controller
def index
if params[:tag]
#apartments = Apartment.tagged_with(params[:tag])
else
#apartments = Apartment.all
end
end
routes
resources :apartments do
#...
collection do
get ':tag', to: 'apartments#index', as: :tag
end
#...
I get nice urls by example /apartments/tag1 etc.
I want to show custom content based on the tag name in the apartments index template.
Apartment's index view:
- #appartments.each do |tags|
- case tags.tag_list
- when "tag1"
%p tag1 content
- when "tag2"
%p tag2 content
- else
%p default content
When i go to url apartments/tag1 the text "default content" is show and not "tag1 content".
What am I doing wrong?
There several notes about your code:
Keep your logic away from views. I.e. extract code into helper methods.
Do not use case on Enumerable, in your case it seems like an array. Use include? to check whether element is present inside an array:
1.9.3p194 :001 > a= [:a, :b, :c]
=> [:a, :b, :c]
1.9.3p194 :002 > case a
1.9.3p194 :003?> when :a
1.9.3p194 :004?> p '1'
1.9.3p194 :005?> when :b
1.9.3p194 :006?> p '2'
1.9.3p194 :007?> when :c
1.9.3p194 :008?> p '3'
1.9.3p194 :009?> when :d
1.9.3p194 :010?> p 'Never'
1.9.3p194 :011?> end
=> nil
1.9.3p194 :012 > a.include?(:c)
=> true
I have a simple user model with a name and settings. After every save of user AREL is performing an update to the settings column. For example:
user = User.find_by_name('kevin')
user.save
(0.3ms) UPDATE "users" SET "updated_at" = '2011-10-20 19:58:06.363541', "settings" = '--- {}' WHERE "users"."id" = 1
None of the other fields are updated when calling save. Is this expected behavior? Why is it performing the update? Can it be turned off to not change if the serialized contents haven't changed? I've uploaded the sample project used to create a minimum case:
http://cl.ly/0p0j3Z3Y0L1x1I1p3Z0g
This is expected behavior. It is very difficult to detect changes within a serialized attribute, so they are updated on every save.
Consider the following (ruby 1.8.7) irb session:
ruby-1.8.7-p352 :001 > x = "--- \n:b: 2\n:a: 1\n"
=> "--- \n:b: 2\n:a: 1\n"
ruby-1.8.7-p352 :002 > y = "--- \n:a: 1\n:b: 2\n"
=> "--- \n:a: 1\n:b: 2\n"
ruby-1.8.7-p352 :003 > x == y
=> false
ruby-1.8.7-p352 :004 > YAML.load(x) == YAML.load(y)
=> true