Rails 4 after_initialize not getting called on find - ruby-on-rails

In a rails 4 (currently 4.0.10) application model I was having a problem with a method not defined for NilClass error in a view, and so I decided to try to solve by setting a sometime nil to an empty string in the model's after_initialize thusly:
def after_initialize
...
self.biography ||= ""
end
because, according to the docs here http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html , "after_initialize callback is triggered for each object that is found and instantiated by a finder"
yet, it appears that after_initialize never gets called and so the error persists, as tested in the rails console:
2.1.1 :001 > Presenter.find(2)
=> #<Presenter id: 2, mediahub_id: 2, name: "Craig", asset_id: nil, biography: nil, status: "active", created_at: "2015-08-12 23:00:34",
updated_at: "2015-08-12 23:00:34">
as you can see, biography is still nil after the find. What am I doing wrong? :)

Related

Rails: ActionText has_rich_text returns nil

I've added ActionText into my Rails 5.2 app, according to this tutorial. I performed installation, migration and added action_text_rich_texts column. I also updated my model:
class LiveEvent < ApplicationRecord
has_rich_text :description_long
end
However has_rich_text helper seems to not working. When I try to initialize new record this way:
#live_event = LiveEvent.new(live_event_params)
description_long attribute returns nil because of this helper. Which crashes my app due to the validation constrains.
Strong param permission for description_long it's also not a case since that attribute was permitted before. This error occurs even if I want to add new record directly through the Rails console:
le = LiveEvent.new(description_long: 'test')
le[:description_long] // returns nil
Maybe there is no established binding between action_text_rich_texts and my LiveEvent model? I'm not sure what it the possible cause of this error. How can I fix it?
ActionText is providing polymorphic association with Model we mention has_rich_text.
So when we define has_rich_text is actually we are defining an association, like we do has_one, 'has_many', belongs_to.
So when you write
#live_event = LiveEvent.new(description_long: 'test')
It will create a new instance of ActionText::RichText model and assign the "text" in the body column as instance of ActionText::Content. So what ever value we assigned to description_long as rich text will automatically wrapped into into a div tag <div class="trix-content">.
Here is the example.
pry(main)> e = Email.new(content: "Asd")
=> #<Email:0x00007fd612746018
id: nil,
user_id: nil,
subject: nil,
created_at: nil,
updated_at: nil>
pry(main)> e.content
=> #<ActionText::RichText:0x00007fd612745c80
id: nil,
name: "content",
body: #<ActionText::Content "<div class=\"trix-conte...">,
record_type: "Email",
record_id: nil,
created_at: nil,
updated_at: nil>
pry(main)> e[:content]
=> nil
pry(main)> e.content.body.to_s
=> "<div class=\"trix-content\">\n Asd\n</div>\n"
so content in this example is not actually a column but it's a association. same way description_long in your example is an association not a column.
Please fine the note below "Note: you don't need to add a content field to your messages table." here in this guide https://edgeguides.rubyonrails.org/action_text_overview.html

Rails callback executed after all fields have been initialized

How can I create a callback in the model which gets called after all the fields have been initialized?
I tried using an after_initialize callback like so:
class Article < ActiveRecord::Base
after_initialize :print_self
def print_self
pp self
end
However, at this time all fields are nil, as ilustrated by the print statement:
#<Article:0x007f8bea51a298
id: nil,
name: nil,
body: nil,
url: nil,
published_at: nil,
created_at: nil,
updated_at: nil,
guid: nil,
summary: nil>
The callback you have created in the above code is correct. The issue I see here is that I don't see any code for initializing the model such as 'new', which will assign values to your attributes.
In the absence of this, none of your attributes have any values.
You may ask, why does 'id' not have a value, but this is because ids are only created and assigned when a record is actually created/saved.
You need something along the lines of:
Article.new(:name => 'My Article')
in your controller or just go to the rails console and do the following:
article = Article.new(:name => 'My Article')
to initialize an Article.

Rails how to improve if record exists?

I have this model:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last
end
end
As you can see, I have a method to get the last event for the device. Now, elsewhere in the Device model I have this method:
def place
self.last_event.place
end
Now, if I don't have any records in Events for this Device I get an error "undefined method `place' for nil:NilClass".
And so I added:
def place
self.last_event.place if self.last_event.present?
end
And this pattern repeated itself throughout the app, I had to add "if self.last_event.present?" so it won't crash in other places too.
I am sure there must be a better way to handle this kind of thing without the need to check if last_event is present everywhere?
Any suggestions?
Thanks,
The try method (an addition of ActiveSupport) allows exactly that. If called on a nil object, it will just return nil too. Thus, both of the following lines are equivalent:
self.last_event.try(:place)
# equivalent to
self.last_event.place if self.last_event
Another option would be to have the method return a blank object which would respond to calls:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last || Event.new
end
def place
self.last_event.place
end
end
2.0.0p247 :001 > d = Device.new
=> #<Device id: nil, name: nil, created_at: nil, updated_at: nil>
2.0.0p247 :002 > d.place
=> nil
2.0.0p247 :003 > d.last_event
=> #<Event id: nil, device_id: nil, created_at: nil, updated_at: nil, place: nil>
The idea is that if a method always returns an object of the expected type, you never have to worry about subsequent calls encountering a nil object. Of course, this could have other implications - such as the need to determine if you have a valid object or a new one, but this can be checked later with:
2.0.0p247 :005 > d.last_event.new_record?
=> true
In that case you can use delegates
delegate :last, to: events, allow_nil: true, prefix: :event
delegate :place, to: event_last, allow_nil: true

rails Model.create(:attr=>"value") returns model with uninitialized fields

This is really stumping me. The process works fine if I go about it with #new and then #save, but #create returns a model instance with all the fields set to nil.
e.g:
Unexpected behavior:
ruby-1.9.2-p0 > EmailDefault.create(:description=>"hi")
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
Expected behaviour:
ruby-1.9.2-p0 > e = EmailDefault.new
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p0 > e.description = "hi"
=> "hi"
ruby-1.9.2-p0 > e.save
=> true
ruby-1.9.2-p0 > EmailDefault.last
=> #<EmailDefault id: 4, description: "hi", created_at: "2011-02-27 22:25:33", updated_at: "2011-02-27 22:25:33">
What am I doing wrong?
--update--
Turns out I was mis-using attr_accessor. I wanted to add some non-database attributes, so I did it with:
attr_accessible :example_to, :cc_comments
which is wrong, and caused the situation #Heikki mentioned. What I need to do is:
attr_accessor :example_to, :cc_comments
You need to white list those properties with attr_accessible to enable mass-assignment.
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible
--edit
By default all attributes are available for mass-assignment. If attr_accessible is used then mass-assignment will work only for those attributes. Attr_protected works the opposite way ie. those attributes will be protected from mass-assignment. Only one should be used at a time. I prefer the white listing with attr_accessible.

Rails 3 Serialization issue

I have an application that was working fine with ror 2.3.x. I am having trouble upgrading to Rails 3 with serialization.
The code looks like this
class PaymentTransaction < ActiveRecord::Base
serialize :response
end
The response is supposed to contain the ActiveMerchant::Billing::Response. With rails 3 for some reason its being save as string.
=> #<PaymentTransaction id: 11, order_id: nil, amount: nil, mode: nil, payment_profile_id: nil, response: "#<ActiveMerchant::Billing::Response:0x1051aec98>", created_at: "2010-11-07 04:06:03", updated_at: "2010-11-07 04:24:58", result: "pending", payee: nil, login_id: nil, transaction_key: nil>
I didn't any notes on serialization in any other blogs talking about upgrade. Any thoughts?
The Rails 2 explanations for using serialization did not work in Rails 3 for me unless I also specified the type of the serialized object in the serialize call. For example:
serialize :response, Array
After specifying array the functionality worked as expected.
Further documentation here:
http://api.rubyonrails.org/classes/ActiveRecord/Base.html
under "Saving Arrays [...]"
There was a small change in rails 3 which have an effect: https://github.com/rails/rails/commit/c1d73270717f30498f8f4d55d6695509107c2834
There are two good blog posts about serialization here:
http://www.simonecarletti.com/blog/2010/04/inside-ruby-on-rails-serializing-ruby-objects-with-json/
http://www.skorks.com/2010/04/serializing-and-deserializing-objects-with-ruby/

Resources