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.
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 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
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
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.
I'm trying to setup single table inheritance in my Rails app for a User model and its subclasses Member, Subscriber, and Staff.
I have a model file for each: user.rb, member.rb, etc
The user model is defined: class User < ActiveRecord::Base; end;
I subclassed the other models as such: class Member < User; end; and so on.
In my users table I have all the fields every class needs plus the type field. Now when I go to the console and try to create a new instance of say member or subscriber i get the following error:
TypeError: can't dup NilClass
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'dup'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'scoped_methods'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2188:in 'current_scoped_methods'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2171:in 'scoped?'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'send'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'initialize'
from (irb):6:in 'new'
from (irb):6
Rails know the subclasses models are there because in the console when I simply call Member or Subscriber, i get the class definition returned.
I've read the simple documentation, but I must be missing something?
I tried on my side starting from a scratch application and it works
Here is my User model (User.rb)
class User < ActiveRecord::Base
end
My member model (Member.rb)
class Member < User
end
I have one migration file to create my users table which contains:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.timestamps
end
end
def self.down
drop_table :users
end
end
Now launching the console:
➜ ./script/console
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, created_at: nil, updated_at: nil>
>> m.name="hop"
=> "hop"
>> m.save
=> true
However I did not manage to reproduce your error :(
Do you have a type column of type varchar (string in ruby)? Try the following commands (in a new rails project)
class Member < User
end
C:\projects\test\sti>ruby script\generate model user name:string type:string membertype:string
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/user.rb
create test/unit/user_test.rb
create test/fixtures/users.yml
create db/migrate
create db/migrate/20091019051506_create_users.rb
C:\projects\test\sti>rake db:migrate
(in C:/projects/test/sti)
== CreateUsers: migrating ====================================================
-- create_table(:users)
-> 0.0000s
== CreateUsers: migrated (0.0000s) ===========================================
C:\projects\test\sti>ruby script\console
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, type: nil, membertype: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, type: "Member", membertype: nil, created_at: nil, updated_at: nil>
>> m.name = 'fred'
=> "fred"
>> m.save
=> true
>> u.name = 'rader'
=> "rader"
>> u.save
=> true
>> User.find :all
=> [#<Member id: 1, name: "fred", type: "Member", membertype: nil, created_at: "2009-10-19 05:17:11", updated_at: "2009-10-19 05:17:11">, #<User id: 2, name: "rader", type: nil, membertype: nil, created_at: "2009-10-19 05:17:24", updated_at: "2009-10-19 05:17:24">]
>>
Check this page, there are more than few solutions to this problem (even in comments).
http://strd6.com/2009/04/cant-dup-nilclass-maybe-try-unloadable/
I'm thinking that the problem is in one of your model definitions because of the stack trace you show. If you still are having a problem, pastie your code, and i'm sure you'll get a good answer.
I hade exactly this problem, after I extracted some functionality to a plugin.
But i my case it worked from the console, so i made sure id reloaded, with this line in init.rb
ActiveSupport::Dependencies.load_once_paths.delete(
File.expand_path(File.dirname(__FILE__))+'/app/models')
I ran into something similar a while back and this website helped:
http://www.dansketcher.com/2009/05/11/cant-dup-nilclass/
class User < ActiveRecord::Base
unloadable
...
end
Not sure why this occurs as I could not track down anything abnormal. I do believe it was a STI situation though.