Rails 3 NoMethodError (undefined method `unserialized_value' for "--- []\n":String): - ruby

I am using Rails 3.2.13 and postgress.
I am getting below error only in production server
NoMethodError (undefined method `unserialized_value' for "--- []\n":String):
app/controllers/blogs_controller.rb:159:in `content_generators'
I am serializing Array to store it in db. Below is code.
Controller
class BlogsController < ApplicationController
def content_generators
#blog = Blog.find(params[:id])
#users = #blog.content_generators.map do |id|
User.find(id)
end
end
end
Model
class Blog < ActiveRecord::Base
serialize :post_access, Array
serialize :content_generators, Array
attr_accessible :post_access, :content_generators
end
Migration
class AddContentgeneratorsToBlog < ActiveRecord::Migration
def change
add_column :blogs, :content_generators, :string, :default => [].to_yaml
end
end
I have already used serialization. You can see post_access is serialized. And that works perfect.
But now when I added another column content_generators it starts breaking.
Thanks for your help in advance.

Since you are using postgresql I strongly recommend using the built in array functionality:
# Gemfile
gem 'postgres_ext'
class MyMigration
def change
add_column :my_table, :that_array_column, :text, array: true, default: []
end
end
Then remove the serialize calls in your model and that's it. PG serialized array's behave exactly the same as YAML serialized ones on the model, except the db supports some query methods on them.

Related

NameError when assigning instance of model to reference property

I'm unable to assign a model instance to a reference property of another model. Relevant code is below:
module Blog::Models
class Post < Base; belongs_to :user, dependent: :destroy end
class User < Base; has_many :posts end
...
class BasicFields < V 1.0
def self.up
create_table User.table_name do |t|
...
end
create_table Post.table_name do |t|
...
t.references :user
end
end
...
end
end
module Blog::Controllers
...
class PostEditN
...
def post(post_num)
#post = Post.find(post_num)
#user = User.find(#input.user)
...
#post.user = #user # Error thrown: NameError at /post/edit/1 uninitialized constant User
# #post.user_id = #user.id << This is my currently working solution
#post.save
redirect PostN, post_num
end
end
...
end
...
When I assign something to #post.user using Camping in console mode, it is successful, but I can't seem to accomplish the same behavior in the controller otherwise. I made do by simply assigning the #user.id to the user_id property of the Post instance. However, I would like to figure out why the alternate method works in the Camping console and not when I'm simply running the webserver.
My best guess is that this is a problem with namespaces. In the code you show Useris actually Blog::Models::User. In your controller the context is Blog::Controllers. Have you tried changing the code in the controller to?
#post = Blog::Models::Post.find(post_num)
#user = Blog::Models::User.find(#input.user)
...
I was able to resolve my issue. Seems when I was creating new Post records, I was not initializing the User. Thus, when assigning #post.user it would complain that the user property was uninitialized. The only problem I see is that an operation was attempted to be made on an oprhan Post record, which is invalid data according to the relationship with User.

Adding a Hash to an ActiveRecord Hash

I read How to add a Hash object to an ActiveRecord class? Tried but migration fails and followed the format there.
I tried:
class AddTestResponsesToSurveys < ActiveRecord::Migration
def change
add_column :surveys, :responses, :hash
end
end
When I run rake db:migrate, I get an error in my schema.rb file that says:
# Could not dump table "surveys" because of following StandardError
# Unknown type 'hash' for column 'responses'
What am I doing wrong?
generate migration with column type text
class AddTestResponsesToSurveys < ActiveRecord::Migration
def change
add_column :surveys, :responses, :text
end
end
And in your Survey model, add this
serialize :responses, Hash

Confusion about ways to use JSON in ruby sinatra application

I'm making a Ruby Sinatra application that uses mongomapper and most of my responses will be in the JSON form.
Confusion
Now I've come across a number of different things that have to do with JSON.
The Std-lib 1.9.3 JSON class: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html
The JSON Gem: http://flori.github.io/json/
ActiveSupport JSON http://api.rubyonrails.org/classes/ActiveSupport/JSON.html because I'm using MongoMapper which uses ActiveSupport.
What works
I'm using a single method to handle responses:
def handleResponse(data, haml_path, haml_locals)
case true
when request.accept.include?("application/json") #JSON requested
return data.to_json
when request.accept.include?("text/html") #HTML requested
return haml(haml_path.to_sym, :locals => haml_locals, :layout => !request.xhr?)
else # Unknown/unsupported type requested
return 406 # Not acceptable
end
end
the line:
return data.to_json
works when data is an instance of one of my MongoMapper model classes:
class DeviceType
include MongoMapper::Document
plugin MongoMapper::Plugins::IdentityMap
connection Mongo::Connection.new($_DB_SERVER_CNC)
set_database_name $_DB_NAME
key :name, String, :required => true, :unique => true
timestamps!
end
I suspect in this case the to_json method comes somewhere from ActiveSupport and is further implemented in the mongomapper framework.
What doesn't work
I'm using the same method to handle errors too. The error class I'm using is one of my own:
# Superclass for all CRUD errors on a specific entity.
class EntityCrudError < StandardError
attr_reader :action # :create, :update, :read or :delete
attr_reader :model # Model class
attr_reader :entity # Entity on which the error occured, or an ID for which no entity was found.
def initialize(action, model, entity = nil)
#action = action
#model = model
#entity = entity
end
end
Of course, when calling to_json on an instance of this class, it doesn't work. Not in a way that makes perfect sense: apparantly this method is actually defined. I've no clue where it would come from. From the stack trace, apparently it is activesupport:
Unexpected error while processing request: object references itself
object references itself
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:75:in `check_for_circular_references'
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `block in encode_json'
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `each'
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `map'
/home/id833541/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `encode_json'
But where is this method actually defined in my class?
The question
I will need to override the method in my class like this:
# Superclass for all CRUD errors on a specific entity.
class EntityCrudError < StandardError
def to_json
#fields to json
end
end
But I don't know how to proceed. Given the 3 ways mentioned at the top, what's the best option for me?
As it turned out, I didn't need to do anything special.
I had not suspected this soon enough, but the problem is this:
class EntityCrudError < StandardError
..
attr_reader :model # Model class
..
end
This field contains the effective model class:
class DeviceType
..
..
end
And this let to circular references. I now replaced this with just the class name, which will do for my purposes. Now to_json doesn't complain anymore and I'm happy too :)
I'm still wondering what's the difference between all these JSON implementations though.

Defining method_missing on Active record in rails 4 throws SystemStackError: stack level too deep on attributes

I recently upgraded my app to rails 4.0 and ruby 2.0
I'm having problems understanding why my method_missing definitions won't work. I'm pretty sure I'm not doing anything differently than I was before.
Specifically, I'm trying to create a method that lets an ActiveRecord object respond to a call to an object it belongs_to via a polymorphic relationship.
Here are my classes:
song.rb
class Song < ActiveRecord::Base
has_many :events, :as => :eventable
end
event.rb
class Event < ActiveRecord::Base
belongs_to :eventable, :polymorphic => true
def method_missing(meth, *args, &block)
if meth.to_s == self.eventable_type
self.eventable
else
super
end
end
end
I want to be able to call event.song when the eventable_type of event == 'Song'
The issue is on the self.eventable_type, which triggers a stack overflow.
What am I missing here?
It seems as though the eventable_type method isn't yet defined when method_missing triggers (some methods in Rails get dynamically defined through method_missing the first time you call them).
I'd try a different means of getting the value you want; perhaps self.attributes["eventable_type"] will work?

Testing before_create method in rspec and rails 3

I've looked into some tutes and all I saw were old posts on how to test before_create. Also it seems like they're all just testing that before_create was called i.e.:
#user = User.new
#user.should_receive(:method_name_called_by_before_create)
#user.send(:before_create) (sometimes they just do #user.save)
I want to actually test that my method worked and that it had assigned(and saved the variables) after creating the record.
Here are my models:
user.rb
class User < ActiveRecord::Base
has_one :character, :dependent => :destroy
after_create :generate_character
private
def generate_character
self.create_character(:name => "#{email}'s avatar")
end
end
and character.rb
class Character < ActiveRecord::Base
belongs_to :user
before_create :generate_character
private
def generate_character
response = api_call
#API CALL HERE
#set object attributes here
self.stat1 = calculate_stat1(response) + 5
self.stat2 = calculate_stat2(response) + 5
self.stat3 = calculate_stat3(response) + 5
end
def api_call
return api_call_response
end
end
I want to test that generate character indeed set the attributes without going online and calling the API call. Is this possible with rspec? I have a fixture of a json response so I was hoping I can stub out generate character and then use the fake response for testing.
Here's my character.spec:
describe Character do
before(:each) do
Character.any_instance.stub!(:api_call).and_return(fake_response.read)
#user = Factory(:user)
#character = #user.character
puts #character.inspect
end
def fake_response
File.open("spec/fixtures/api_response.json")
end
It prints out only 5 for each of the character's stats. Also I did a puts response in the generate_character method in character.rb and it still prints out the "real" api call.
I managed to do a puts in fake_response and it does goes through there but it also goes through the "real" api_call after, which makes the stub obsolete. How do I get through this?
A good approach here is extracting your api call into a self contained method. Something like this:
class Character < ActiveRecord::Base
belongs_to :user
before_create :generate_character
private
def generate_character
data = api_call
#set object attributes from data
end
def api_call
# returns a data structure
# resulting from the call
end
end
Then use RSpec's any_instance to stub the api_call method to return a fixed data structure
Character.any_instance.stub!(:api_call).and_return { {:id => 1, :attribute_one => "foo"} }
#user = User.create
#user.character.attribute_one.should == "foo"
for more info on any_instance check this commit

Resources