Rails model returning nil ID - ruby-on-rails

I need to get the id of a certain object. It's probably something really simple that I am missing. The object I need comes out from the database, and I'm able to retrieve its attributes but not the id.
Part.where("code ='p8z68vprogen3'").first
# => <Part id: 486, code: "p8z68vprogen3", etc...>
Part.where("code ='p8z68vprogen3'").first.id
# => nil
Part.where("code ='p8z68vprogen3'").first.code
# => "p8z68vprogen3"
This is the model:
class Part < ActiveRecord::Base
has_many :build_parts
has_many :builds, :through => :build_parts
belongs_to :category
attr_accessible :code,:link,:description,:category_id
end
I suppose it's something related to attr_accessible or attr_accessor, I tried to fiddle with them but nothing so I ask for help.
EDIT:
asking for a reload returns an error in any way i try i get the object(where or find_by_)
part_needed = Part.where("code ='p8z68vprogen3'").first
# => <Part id: 486, code: "p8z68vprogen3", etc..>
part_needed.reload
# ActiveRecord::RecordNotFound: Couldn't find Part without an ID
Also, the parts table is already populated, but here is the code that creates an entry:
part = Part.new(
:description => objs[1],
:code => objs[2],
:category_id => tips[objs[3].to_i]
)
part.save!
This code is executed in another part of the code is not just before where I try to get the ID.

Restart your machine. I know it doesn't sound logical. I encountered a problem where I had two objects of the same class and the first/last method returned the last object. Restarting worked for me. (rails 3.1.1, ruby 1.9.2p320 (2012-04-20 revision 35421) [i686-linux])
)

Related

How to disregards the object while querying using ActiveRecord::Base methods whose associated object has been deleted from database in rails

I have Person<ActiveRecord::Base model
class Person < ActiveRecord::Base
has_many :sent_messages, :class_name => 'Message', :inverse_of => :sender
has_many :received_messages, :class_name => 'Message', :inverse_of => :receiver
#.....
end
and another modeActiveRecord::Base model
class Message < ActiveRecord::Base
belongs_to :sender, :class_name => 'Person'
belongs_to :receiver, :class_name => 'Person'
# ......
end
; and ActiveRecord::Migration class supporting these models. Now my problem is that I need to output the messages received by current user with the Person name of sender by querying database, but while querying it seems that some of the person(user) who sent the messages has been deleted from database(but messages once exchanged b/w two persons is saved permanently in database and no body have the permission to delete it, So each message will be there with all the details like receiver_id and sender_id .). So when I query like this.
#messages = Message.where(:receiver_id => current_user.id)
.includes(:sender).order("updated_at DESC")------------(1)
it works fine if person who has sent the message to currently logged in user has it's delete_at attribute null(meaning not deleted from database and can be used without any error in views for sender name) but for those which has been deleted it gives this error in browser console
in application controller asset is undefined method or variable ----------(2)
where a method in application controller to handle no record found exception
def respond_to_not_found(*types)
flash[:warning] = t(:msg_asset_not_available, asset)
respond_to do |format|
format.html { redirect_to(redirection_url) }
# ...
end
end
please tell What is the t and asset is in answer ???
So as a workaround of problem (1) -------- (3).
I queried this and
def show_list
#messages = Array.new
#person = Array.new
messages_temp = Message.where(:receiver_id => current_user.id).
includes(:sender).order("updated_at DESC")
i = 0
messages_temp.each do |msg|
if(!(msg.sender.nil?))
#messages[i] = msg
#person[i] = msg.sender
i = i+1
end
end
end
My questions:-
Q.1) I haven't much worked with database so this is valid question for me(as the project I am working on explicitly destroys the requested user):- Why the user info has not been deleted from database but rather it's deleted_at attribute has become not null whereas for others which are intact have same attribute null. And when I find(query by method find) an object of Person from database then while querying it's SQL conversion query for deleted_at attribute should be null. So why is happening am I missing something in my project code or it is general behaviour. If it general then how to completely expunge the data.
Even if such behaviour is general or not how to recover it, without manually changing each deleted Person deleted_at attribute to null. And how to access some of it's attribute without fully restoring the Person(or if such thing is possible).
Q.2) What might be other reasons for getting error #(2) even after workaround. As I tested the workaround and it worked fine for some of deleted sender's. But even after at some places I am getting error #(2) so in general what does this error stand for and what might be it's other cause then the one I mentioned???
Q.3)Is there better solution then the workaround given in eq #(3) because you see in my workaround msg.sender.nil? is true for the deleted object so I think there might be some. I tried the net but with no success. So, how to filter out those messages whose associated object is deleted how to query them all at once then doing it one by one as in #(2).
As workaround is giving me hard time to paginate the output because all the available pagination gem (for example 'will_paginate', 'kaminari', 'pagination') works on ActiveRelation but in my workaround I have Array object i.e #messageson which I can not use these methods. So it would be great help if one can answer a way to paginate my workaround i.e object #messages which is an array or a way to filter out those messages whose sender is deleted from database then I can paginate in this way :-
#messages = Message.<ActiveRecord::Base method to get the desired output>.paginate[params]
PS:- I know the question is tedious but I believe it is essential for this question I am seeking answer to. Any help will be appreciated even the partial answer to the question.
Thanks a lot!!!
Ok...
Well it took me couple of days but with some help from my vicinity I did figure out answer to most of the confusion and ambiguity:
Ans:-
1:) There is a way to soft delete the data meaning hidden from normal query... Most of ambiguities of question one can be answered from this [link][1]. This gem(acts_as_paranoid) helps soft deleting the data. yes, attributes of soft deleted object can be accessed without restoring the date; and data can be completely expunged as well(everything in the link). The changes I needed to make in my code base to avail these benefits are these:-
In Person<ActiveRecord::Base model
class Person < ActiveRecord::Base
# has_many :sent_messages, :class_name => 'Message', :inverse_of => :sender
# has_many :received_messages, :class_name => 'Message', :inverse_of => :receiver
has_many :sent_messages, :class_name => 'Message',
:inverse_of => [:sender, :sender_including_deleted]
has_many :received_messages, :class_name => 'Message',
:inverse_of => [:receiver, :receiver_including_deleted]
#.....
end
and in the model ActiveRecord::Base
class Message < ActiveRecord::Base
belongs_to :sender, :class_name => 'Person'
belongs_to :receiver, :class_name => 'Person'
# Add these two lines:-
belongs_to :sender_including_deleted, :class_name => 'Person',
:foreign_key => 'sender_id', :with_deleted => true
belongs_to :receiver_including_deleted, :class_name => 'Person',
:foreign_key => 'receiver_id', :with_deleted => true
# ......
end
So, adding these two lines worked for me but most importantly the gem helped me a lot.
2:) One of prominent reason for getting error in (2) is that one may be trying to directly access the attribute of object which may be deleted. Suppose a Person is deleted(soft or hard doesn't matter whose id was 15) so first_name = Person.find(15).first_name will give error where as person = Person.find(15) if(!person.nil?) return first_name will not as we are checking if returned person is nil or not. and if Person is deleted with gem acts_as_paranoid then a soft deleted(meaning deleted_at attribute is not null. The deleted_at(this attribute has to be added in migration to use) attribute is updated when object is deleted for clear picture see the embedded link here) object accessed first_name = Person.with_delete.find(15) like this won't generate an error
Note:- I don't what might be other reason. please answer this part if you can think of any.
3:) Although I do not have direct answer to question asked in 3 but since now I can access the message sender info even though they are deleted(in active relation form) so ordering and pagination works but I surely like to know how to paginate if object in not active relation.
So, this one I best answered like this:-
def show_list
# #messages = Array.new
# #person = Array.new
# messages_temp = Message.where(:receiver_id => current_user.id).
# includes(:sender).order("updated_at DESC")
# i = 0
# messages_temp.each do |msg|
# if(!(msg.sender.nil?))
# #messages[i] = msg
# #person[i] = msg.sender
# i = i+1
# end
# end
# REPLACE ABOVE CODE BY THIS. THe following code will
# include deleted messages as well.
#person = Array.new
#messages = Message.where(:receiver_id =>current_user.id).
includes(:sender_including_deleted).
order("created_at DESC").paginate(params).readonly
i = 0
#messages.each do |msg|
#person[i] = msg.sender_including_deleted(:with_deleted => true)
i = i + 1
end
end
I hope the people who stumbled upon this question get what they are looking. If they didn't get any part of my answer or question then they are welcome to comment here and I will be happy to answer to best of my abilities.

ActiveRecord::MissingAttributeError (can't write unknown attribute) in Rails

I want to create a new "AnswerStat" object and save it in the database. I am getting:
can't write unknown attribute `answer_stat_id'
app/models/answer_stat.rb:14:in `new'
app/models/answer_stat.rb:14:in `add_answer'
app/controllers/users_controller.rb:31:in `block in index'
app/controllers/users_controller.rb:30:in `each'
answer_stat_id does not exist, it refers I guess to the primary key of the table answer_stats which is id. I do not explicitly declare this attribute of course. Why is Rails looking for this inexistent attribute? Code:
class AnswerStat < ActiveRecord::Base
attr_accessible :contact, :statement, :answer_sum, :answer_count, :variation
belongs_to :contact, :class_name => "Friend"
has_one :statement
validates_uniqueness_of :contact, :scope => :statement
def self.add_answer(answer)
if stat = AnswerStat.find_by_contact_id_and_statement_id(answer.contact.id, answer.statement.id)
...........do some stuff...........
else
#answer_stat = AnswerStat.new(:contact => answer.contact, :statement => answer.statement, :answer_count => 1, :answer_sum => answer.description, :variation => answer.description)
#answer_stat.save
end
end
I am calling it from the rails console, or from any controller, using:
Answer.all.each do |a|
AnswerStat.add_answer(a)
end
The answer_stats table (sqlite3 using PRAGME table_info(answer_stats)):
0|id|INTEGER|1||1
1|contact_id|integer|0||0
2|answer_sum|integer|0||0
3|answer_count|integer|0||0
4|created_at|datetime|1||0
5|updated_at|datetime|1||0
6|statement_id|integer|0||0
7|variation|integer|0||0
Thanks in advance
it could come from the statement attribute, which refers to an associated model.I think it's looking for an answer_stat_id foreign key in the statements table.
You should either :
create the associated answer via #answer_stat.build_statement(...)
redesign your model associations if the statement is meant to preexist the stat

Rails validation fails even when data is entered

Here is the command that I'm executing in Rails Console:
Person.create!(:firstName=>"matt", :lastName=>"master", :gender => 1)
My result is this error message:
ActiveRecord::RecordInvalid: Validation failed: Firstname can't be blank
My model validation code looks as such:
class Person < ActiveRecord::Base
belongs_to :user, :class_name => 'User', :foreign_key => 'fk_ssmUserId'
validates_presence_of :firstName, :lastName
When I comment out validates_presence_of everything works and my data is entered properly into the database, so I know that the values are actually being passed into the new object. I even inspected the new object created inside the Rails::ActiveRecord::Validations code to make sure it was being instantiated correctly before being saved. It was. Also, I have other models with validates_presence_of that work 100% fine every time. It's just this one model. I am using Rails 3.1.0.rc1.
Any ideas?
Thanks!
:firstName=>"matt", :lastName=>"master", :gender => 1
check that the key correspond to your model columns. Seems to be everything should be fine.
I have a suspicion that this error relates to the fact that you're creating and saving the object using the .create! method from the console. Your Person class appears to require a foreign key, a value which is probably not being instantiated when you create an object at the console. To test this, try typing:
test = Person.create(:firstName=>"matt", :lastName=>"master", :gender => 1)
with no bang after the .create method. This should not generate an error. Now type:
test
It's very likely that you have required key values set as "nil" and that the object can't be saved from console until you fill in the appropriate values.

Internal messaging in Rails

I'm using this tutorial to get internal messages working on my site: http://www.novawave.net/public/rails_messaging_tutorial.html
But, since my latest upgrade to Rails 3, I'm getting this error:
NoMethodError in MsgController#sendmsg
undefined method `each' for #<String:0xcc8acc0>
Application trace:
app/models/message.rb:16:in `prepare_copies'
app/controllers/msg_controller.rb:140:in `sendmsg'
The Message model:
class Message < ActiveRecord::Base
belongs_to :author, :class_name => "User"
has_many :message_copies
has_many :recipients, :through => :message_copies
before_create :prepare_copies
attr_accessor :to # array of people to send to
attr_accessible :subject, :body, :to
def prepare_copies
return if to.blank?
to.each do |recipient|
recipient = User.find(recipient)
message_copies.build(:recipient_id => recipient.id, :folder_id => recipient.inbox.id)
end
end
end
That tutorial seems a bit dated. It uses Rails 2.0 (and probably some equally old Ruby version).
Are you sure that to holds an Array (as indicated in your attr_accessor comment)? The error message seems to indicate that it is a String.
Did you previously have this code running under Ruby 1.8 (and, presumably, a version of Rails 2.3)?
In Ruby 1.8 you could send each to String instances and it would (by default) iterate on the lines of the string (actually it would split on $/ and iterate on the result).
In Ruby 1.9 you need to use each_line to iterate over the lines of a string.
to.each_line do |recipient|
…
end
Seems you to is no anymore an Array but a String now. You problem semmes becomes from your controller and how you define your to accessor inside it.

Getting a NameError with ActiveRecord and relationships

I've run into a problem when using a one to many relationship. I want to have each Series have one Publisher and that one Publisher has many Series.
This is my Publisher model:
class Publisher < ActiveRecord::Base
validates_presence_of :name
has_many :series
end
This is my Serie model:
class Serie < ActiveRecord::Base
belongs_to :publisher
end
This is the failing test:
test "a publisher should have a list of series" do
#publisher = Publisher.new :name => "Standaard Uitgeverij"
#series = [ Serie.new(:name => "De avonturen van Urbanus", :publisher => #publisher),
Serie.new(:name => "Suske en Wiske", :publisher => #publisher) ]
assert_equal #series, #publisher.series
end
The test fails on the last line with NameError: uninitialized constant Publisher::Series.
I tried to save the publisher and the series, but this did not work. I tried it with only one serie, but this gives the same error.
Since I'm just starting out with Rails and Ruby, I am at a loss here. What am I doing wrong?
To address your actual question as mentioned in your comment (how can I name my model "Series"?), you need to make the Rails' Inflector aware of this exception to its default pluralization rules.
Add the following to config/environment.rb:
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable 'series'
end
This will let you name your model as Series. You can test that it's worked using script/console:
>> "series".pluralize #=> "series"
>> "series".singularize #=> "series"
—I have to say that I've just tried using The Pluralizer and it would appear that Rails has knowledge of how to handle the word series built-in. Try it for yourself.
I believe John's answer is the best one.
You can also directly specify the class name in the has_many declaration
has_many :series, :class_name => 'Serie'
Your has_many relationship name is fine, but your model name is wrong.
As the singular and plural of series are both series, you need to rename your model from Serie to Series. After that, everything should be fine.

Resources