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.
Related
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
I'm new to Rails and am working on getting an application set up in Rails 4.2.4. I have a model called List that looks like the following in the database (PostgresQL):
List(id: integer, user_id: integer, name: string, created_at: datetime, updated_at: datetime, friendly_name: string)
and in List.rb:
class List < ActiveRecord::Base
attr_accessor :name, :friendly_name
belongs_to :user
has_many :items
end
I am trying to modify the name attribute from a controller action:
def save_name
...
list_to_edit = List.find(params[:id].to_i)
list_to_edit.name = params[:name]
list_to_edit.save!
...
end
But the changes are not being persisted. I have confirmed that params[:name] and list_to_edit are not nil. When I try to change the attribute in the Rails console like this:
> l = List.last
> l.name = 'TestName'
> l.save!
I don't see any errors. After executing the above commands and executing l.name I do see TestName. When I type l or List.last, however I still see
#<List id: 29, user_id: 17, name: nil, created_at: "2015-11-07 18:55:04", updated_at: "2015-11-07 18:55:04", friendly_name: nil>
What do I need to do to set the name attribute of a List? I can post any additional file content if it is helpful.
After trying a few more things it looks like all I needed to do was remove name from the array being passed to attr_accessor in List.rb. I believe when I was trying to change the list name with my_list.name = 'something' I was modifying the instance variable, not the attribute stored in the database.
Like the title said, I'm trying to get the ID of the record I just created, I tried to get it in the console but the ID is nil.
Here is the print I got of self in the console at the beginning of after_create
<Unit id: nil, uuid: "9f11be13-8d07-4471-a3bb-f87943966bbd", organization_id: 33, property_id: 430, door_number: "3", created_at: "2014-12-05 13:27:57", updated_at: "2014-12-05 13:27:57", deleted_at: nil, size: "5 1/2", door_number_int: 3, leases_count: 0, tasks_count: 0, notes: nil, state_id: 68, state_tasks_count: 2, current_lease_id: nil, next_lease_id: nil, state_tasks_serie: 1, state_tasks_serie_count: 2, price_asked: #<BigDecimal:7fc79162cb80,'0.123E3',9(18)>, availability_date: nil, comments_count: 0>
Is there a way to get access to the record ID?
This is what I tried so far
after_create
self.save
end
before_save
if self.id.present?
# do stuff
end
end
It is not very pretty but it work
To answer #MarekLipka : It doesn't cause an infinite loop because the record is created only once.
I also tried to use :
after_create
reload
# do stuff if self.id
end
but that doesn't seem to work.
Like #PauloFidalgo said, I can't get the id except in the after_save method. Although it is strange to me that I can get it in the second before_save (triggered by the save in after_create).
The id is only assigned on save, on create you are just creating the skeleton object and giving some values.
To get the id of the object just call object.id
If for some reason you want to get the id in the after_* methods, you need to use the after_save:
after_save {id = self.id}
You could also allocate an ID in create, but you need to query the database and set the value in the variable. To achieve this you need to use a sequence in database to set the id's.
Is it possible to set-up a scope on a single table inheritance that returns the subclass?
For example:
class Post < ActiveRecord::Base
scope :sticky, -> { where(type: 'StickyPost') }
end
class StickyPost < Post
end
Now, when I call sticky on a collection of posts I get a collection of StickyPost instances.
But when I call posts.sticky.build, the type is set to StickyPost, but the class still is Post.
posts.sticky.build
=> #<Post id: nil, message: nil, type: "StickyPost", created_at: nil, updated_at: nil>
Update
Apparently this works.
posts.sticky.build type: 'StickyPost'
=> #<StickyPost id: nil, message: nil, type: "StickyPost", created_at: nil, updated_at: nil>
Which is strange, since the scope already sets the type, it seems a bit redundant. Any way to set this behaviour in the scope?
You can make the sticky scope return the correct class by using becomes method in the scope:
class Post < ActiveRecord::Base
scope :sticky, -> { where(type: 'StickyPost').becomes(StickyPost) }
end
The becomes method maps an instance of one class to another class in the single-table inheritance hierarchy. In this case, it maps each instance of Post returned by the sticky scope to StickyPost. With this change, calling posts.sticky.build will now return an instance of StickyPost:
posts.sticky.build
=> #<StickyPost id: nil, message: nil, type: "StickyPost", created_at: nil, updated_at: nil>
I have a standard model with a few fields that are saved to a DB, and I need 1 field that doesn't have to be saved.
I tried attr_accessor but that doesn't cover it. Using Attr_accessor I can set and get the field, but it is not part of the model. If I add the models to an array and then see what is in the virtual field is not part of it. I also tried to add the field :headerfield to attr_accessible but that didn't change anything.
How can I get a field that is part of the model but not saved to the database?
The model
class Mapping < ActiveRecord::Base
attr_accessible :internalfield, :sourcefield
attr_accessor :headerfield
end
console output:
1.9.3-p194 :001 > m = Mapping.new
=> #<Mapping id: nil, internalfield: nil, sourcefield: nil, created_at: nil, updated_at: nil, data_set_id: nil>
1.9.3-p194 :002 > m.headerfield = "asef"
=> "asef"
1.9.3-p194 :003 > m
=> #<Mapping id: nil, internalfield: nil, sourcefield: nil, created_at: nil, updated_at: nil, data_set_id: nil>
Because ActiveRecord::Base has custom implementations for the standard serializiation methods (including to_s and as_json), you will never see your model attributes that do not have backing database columns unless you intervene in some way.
You can render it to JSON using the following:
render json: my_object, methods: [:virtual_attr1, :virtual_attr2]
Or you can use the as_json serializer directly:
my_object.as_json(methods: [:virtual_attr1, :virtual_attr2])
The return you see in the console is nothing else but the value of to_s. For this case, code should be better than natural language, take a look in the following code and see if you understand
class A
end
=> nil
A.new
=> #<A:0xb73d1528>
A.new.to_s
=> "#<A:0xb73d1528>"
class A
def to_s
"foobar"
end
end
=> nil
A.new
=> ble
A.new.to_s
=> "ble"
You can see this output because ActiveRecord::Base defines a method to_s that take into account only the attributes that are defined in the database, not the attr_accessor methods, maybe using the attributes call.