Rails: ActionText has_rich_text returns nil - ruby-on-rails

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

Related

Unable to assign value to an ActiveModel attribute (rails 4.2)

I have created a simple users model in rails 4.2. However I am unable to assign any attribute values in the rails console
2.1.5 :001 > u = User.new
=> #<User id: nil, name: nil, email: nil, auth_token: nil, created_at: nil, updated_at: nil, enabled: true>
2.1.5 :002 > u.name = 'sample'
=> "sample"
2.1.5 :003 > u.changed
=> []
2.1.5 :004 > u
=> #<User id: nil, name: nil, email: nil, auth_token: nil, created_at: nil, updated_at: nil, enabled: true>
As you can see despite setting name the value has not changed.
Here is the model file
class User < ActiveRecord::Base
self.primary_key = :id
include Tokenable
include Creatable
include Updatable
attr_accessor :name, :email, :auth_token, :created_at, :updated_at, :enabled
end
I know that this works fine in rails 3.2
One of the biggest "selling points" of ActiveRecord is that it automatically creates setters and getters in your models based on the DB schema.
These are not just your average accessors created by attr_accessor (which is plain Ruby), they cast values to the correct type and do dirty tracking among other things.
When you use attr_accessor you´re generating setters and getters that clobber those created by ActiveRecord - which means that AR will not track changes or persist the attributes.
This is what you really want:
class User < ActiveRecord::Base
include Tokenable
include Creatable
include Updatable
end
Only use attr_accessor in models when you need setters and getters for non-persisted ("virtual") attributes.
You need to save the record after assigning the new value. You can achieve that by calling update_attribute! or save! on your object. In your case:
u.name = "sample"
u.save!
or
u.update_attribute("name", "sample")
Note that update_attribute updates a single attribute and saves the record without going through the normal validation procedure

Unable to set Rails model attribute from console or controller

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.

Rails: List Required Attributes For Create

I am manually creating objects in the rails console using Model.new(<attributes here>). Is there an easy way to list out which attributes a model will require me to include in order for the .save call to succeed?
I am running rails 4.2.3
You can get an array of validators using Model.validators. You'll have to parse this in some way to extract those validations for presence, something like:
presence_validated_attributes = Model.validators.map do |validator|
validator.attributes if validator.is_a?(ActiveRecord::Validations::PresenceValidator)
end.compact.flatten
I found a simpler way to accomplish the same thing:
When you do a failed create you can check the error message on the object.
# app/models/price.rb
class Price < ActiveRecord::Base
validates_presence_of :value
end
# in console
p = Price.new()
=> #<Price id: nil, created_at: nil, updated_at: nil, value: nil>
p.save
=> false
p.errors.messages
=> {:value=>["can't be blank"]}
In case you the mandatory attributes with error messages
book = Book.new
book.valid?
book.errors.messages
In case you just want the name of attributes without an error message
book = Book.new
book.valid?
book.errors.messages.keys

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.

virtual field in a model part of the model but not in the DB

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.

Resources