How to detach the associated record in memory only which is related to has_many association in rails-4.2 - ruby-on-rails-3

In Rails 3.2.16 we are having association as user has_many activities while querying has_many association, we can detach the association in memory by using the pop method which will not update the database, once we reloading the main object then it will remove changes in memory.
**Rails 3.12.16**
#user = User.find(1) # Identifying the user
#user.activities # Fetching activities of that user having one record
[#<Activity id: 205501, title: "Logging", user_id: 1, created_at: "2020-06-01 14:29:23", updated_at: "2020-06-01 14:29:43">]
#user.activities.pop # will detach the first object and #activities will have an empty array in the whole application until reloading main object
[]
#user.activities # will return []
#user.activities.build(id: 1234567, title: "Signing Out") # will return only new built object
[#<Activity id: 1234567, title: "Signing Out", user_id: 1>]
#user.reload
#user.activities # will retain the association records
[#<Activity id: 205501, title: "Logging", user_id: 133, created_at: "2020-06-01 14:29:23", updated_at: "2020-06-01 14:29:43">]
**Rails 4.2**
#user = User.find(1) # Identifying the user
#user.activities # Fetching activities of that user
[#<Activity id: 205501, title: "Logging", user_id: 133, created_at: "2020-06-01 14:29:23", updated_at: "2020-06-01 14:29:43">]
#user.activities.pop # will throw an error because ActiveRecord::CollectionProxy is not having the pop method
# So we tried the to_a method
#user.activities.to_a.pop # it is affecting the array but not detaching the association in memory due it is not mutated
[]
#user.activities # > Rails 4 the association is reloaded defaultly
[#<Activity id: 205501, title: "Logging", user_id: 133, created_at: "2020-06-01 14:29:23", updated_at: "2020-06-01 14:29:43">]
# If we are trying to build a new object
#user.activities.build(id: 1234567, title: "Signing Out")
#user.activities # We are receiving both existing and new build object but we needed only newly build object like rails 3
[#<Activity id: 205501, title: "Logging", user_id: 133, created_at: "2020-06-01 14:29:23", updated_at: "2020-06-01 14:29:43">,
#<Activity id: 1234567, title: "Signing Out", user_id: 1>]
As Rails Document suggests to use the delete method,
but it is updating the association record in Database and removing the record as well.
Anyone can suggest the replacement of the rails 3.12.16 pop method, in rails 4.2
Currently, we are upgrading our Ruby on Rails application from 3 to 4,2.
Gems Listing:-
Rails 4.2.0 -
1) ruby (2.3.3)
2) activerecord (4.2.0)
Rails 3.2.16 -
1) ruby (2.0.0)
2) activerecord (3.2.16)

According to a rails contributor, this is expected behavior.
See here: https://github.com/rails/rails/issues/30612#issuecomment-329884753
I suspect you're going to have to find a different way to do what you want to do, but you haven't really stated what you're trying to accomplish.

Related

While testing Devise with rspec, it acts like I am not logged in

I'm using Rails 3.2.13, devise 2.2.4, and rspec 2.13.2. I have a multi-tenant app in which the default scope only shows current_user's items. Everything seems to work in development, but my tests are having issues.
Problem: When I create a meal in my test, it shows user_id => nil. In my development environment everything works, though. Also, when I go into debug mode, when I check the #controller.current_user, it shows user_id 1 is logged in. Since in my development environment the user_id is being assigned automatically when I create an object, I can't figure out why it's not doing it during tests. Any ideas?
Here's my abbreviated meals_controller_spec file:
describe MealsController do
include Devise::TestHelpers
describe "When logged in as user," do
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#email = "someone#test.com"
#password = "password"
#user = User.create(email: #email, password: #password)
sign_in #user
end
describe "DELETE destroy" do
it "destroys the requested meal" do
meal = Meal.create!("name" => "", "servings" => "2", "meal_type" => "dinner")
expect { delete 'destroy', {:id => meal.id} }.to change(Meal, :count).by(-1)
end
end
end
end
Here's part of my model:
class Meal < ActiveRecord::Base
belongs_to :user
default_scope { where(user_id: User.current_id) }
Here's part of my controller:
class MealsController < ApplicationController
before_filter :authenticate_user!
def destroy
#meal = Meal.find(params[:id])
#meal.destroy
redirect_to meals_url, :notice => "Successfully deleted #{#meal.name}."
end
end
And I think my application controller could be relevant:
class ApplicationController < ActionController::Base
protect_from_forgery
around_filter :scope_current_tenant
private
def scope_current_tenant
User.current_id = current_user.id
yield
rescue Exception
yield
ensure
User.current_id = nil
end
end
Here's some output when I debug in the middle of that test:
(rdb:1) #controller.current_user.id
1
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2)
#<Meal id: 2, name: "meal", meal_type: "dinner", servings: 2, user_id: nil, created_at: "2013-06-17 06:07:34", updated_at: "2013-06-17 06:07:34">
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2, user_id: 1)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
(rdb:1) Meal.find(3).destroy
*** NoMethodError Exception: undefined method `destroy' for nil:NilClass
So I guess I'm wondering why the user in my test appears to be nil, even though I am using the Devise test helpers and signing in, and in my dev environment everything works.
Edit:
Here are some more debugger results:
(rdb:1) Meal.find(4)
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.find(4).destroy
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.where(:user_id => 1).find(3)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
It appears that the "current user" is in fact user_id => nil, per the sql snippets. So why would that be if I used the Devise test helper sign_in function?

Rails User.all bug found in Hartl's scaffold app - Why is User.all not responding to command like an array of hashes?

I discovered this bug while reproducing Michael Hartl's scaffolded rails demo_app from his rails tutorial.
I went into the rails console
rails c
I asked for the User.all array of hashes and out it through its paces:
2.0.0-p0 :012 > User.all
User Load (0.3ms) SELECT "users".* FROM "users"
=> [#<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06">]
2.0.0-p0 :013 > User.all[0]
User Load (0.2ms) SELECT "users".* FROM "users"
=> #<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06">
2.0.0-p0 :015 > User.all[0]['id']
User Load (0.2ms) SELECT "users".* FROM "users"
=> 2
So far, so good.
However, User.all does not respond to the command to list say just the id's or names of all users:
2.0.0-p0 :017 > User.all { |i| puts i['id'] }
User Load (0.2ms) SELECT "users".* FROM "users"
=> [#<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06"gt;]
2.0.0-p0 :019 >User.all{ |i| puts i['name'] }
User Load (0.3ms) SELECT "users".* FROM "users"
=> [#<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06">]
Assigning an arbitrary variable a to the array of hashes User.all resolves the issue:
2.0.0-p0 :021 >a.each {|i| puts i['id'] }
2
=> [#<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06">]
2.0.0-p0 :022 >a.each {|i| puts i['name'] }
Lisa Johnson
=> [#<User id: 2, name: "Lisa Johnson", email: "ljohnson#yahoo.com", created_at: "2013-04-02 03:30:06", updated_at: "2013-04-02 03:30:06">]
This User.all issue affects at least ruby versions 1.9.2,1.9.3 and 2.0.0. Whoever is responsible for writing the gem that created User.all needs to go over his all method. For whatever it's worth, I am working with rails 3.2.12
Nothing to discuss - its a straightforward bug report. If there is a question, the question would be "why is User.all is not behaving like the array of hashes it is?"

Testing controller new action with Rspec2 + Rails3

I have the following rspec2 test case for my controller new action
describe "GET #new" do
it "should assign new project to #project" do
project = Project.new
get :new
assigns(:project).should eq(project)
end
end
and I'm getting the following error
1) ProjectsController GET #new should assign new project to #project
Failure/Error: assigns(:project).should eq(project)
expected: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
got: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
(compared using ==)
Diff:#<Project:0x007f461c498270>.==(#<Project:0x007f461c801c90>) returned false even though the diff between #<Project:0x007f461c498270> and #<Project:0x007f461c801c90> is empty. Check the implementation of #<Project:0x007f461c498270>.==.
# ./spec/controllers/projects_controller_spec.rb:19:in `block (3 levels) in <top (required)>'
Finished in 1.21 seconds
13 examples, 1 failure, 10 pending
Failed examples:
rspec ./spec/controllers/projects_controller_spec.rb:16 # ProjectsController GET #new should assign new project to #project
and when I use == instead on eq, I'm getting the following error
1) ProjectsController GET #new should assign new project to #project
Failure/Error: assigns(:project).should == project
expected: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
got: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil> (using ==)
Diff:#<Project:0x007f461c4f5420>.==(#<Project:0x007f461c63b280>) returned false even though the diff between #<Project:0x007f461c4f5420> and #<Project:0x007f461c63b280> is empty. Check the implementation of #<Project:0x007f461c4f5420>.==.
what am I doing wrong here, thanks in advance
I'm on
Rails3
Rspec2
You are creating a new project before accessing the new action, this is unnecessary. Your controller actually does that work for you already. The problem you are facing is that you have two new projects created (in your case you have created Project:0x007f461c498270 first and then Project:0x007f461c801c90, they have the same attributes but are different projects). This test should pass:
describe "GET #new" do
it "assigns a new Project to #project" do
get :new
assigns(:project).should be_a_new(Project)
end
end

Rails :include doesn't include

My models:
class Contact < ActiveRecord::Base
has_many :addresses
has_many :emails
has_many :websites
accepts_nested_attributes_for :addresses, :emails, :websites
attr_accessible :prefix, :first_name, :middle_name, :last_name, :suffix,
:nickname, :organization, :job_title, :department, :birthday,
:emails_attributes
end
class Email < ActiveRecord::Base
belongs_to :contact
validates_presence_of :account
validates_format_of :account, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
attr_accessible :contact_id, :account, :label
end
If I run the following query, the emails are returned as expected:
c = Contact.find(3)
Contact Load (3.2ms) SELECT `contacts`.* FROM `contacts` LIMIT 1
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">
c.emails
Email Load (4.4ms) SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` = 3
=> [#<Email id: 3, contact_id: 3, account: "not#real.address", label: "work", created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">]
However, attempting to :include the relationship does not:
c = Contact.find(3, :include => :emails)
Contact Load (0.5ms) SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`id` = 3 LIMIT 1
Email Load (0.8ms) SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` IN (3)
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">
As you can see, the SQL is being executed, but the emails are not being returned. I intend to return all contacts with each containing email(s), so :joins won't do any good. What am I missing?
The emails are there. Did you try c.emails? You will find that the emails will be there without Rails doing an additional DB query.
The thing that :include does is called eager loading, which basically means Rails will try a best effort method of prepopulating your objects with their relations, so that when you actually ask for the relation no additional DB queries are needed.
See the section "Eager loading of associations" here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
You might also want to check out this RailsCast:
http://railscasts.com/episodes/181-include-vs-joins

Tricky active record relationships - polymorphic bi-directional self-referential

How would you model the references and citations to publications (articles, books, chapters, etc...)?
A publication can be an article, book or a chapter and it has many references to other publications and other publications refer to it (call these citations)
I need to be able to list the relationships among the publications: The references in a publication and the citations from other publications to this publication
My initial understanding is that this would be a polymorphic relationship to handle the different types of publications and that it would require a bidirectionalself join.
My stab at it
Publication
belongs_to :writing, :polymorphic =>true
has_and_belongs_to_many :references
:class_name => "Publication"
:join_table => 'reference_citation'
:foreign_key => 'reference_id'
:foreign_key => 'citation_id'
Book, Chapter, Article all have:
has_many :publications :as =>writing
I find this a bit confusing so any suggestions that would help clarify it would be great. Even object and field naming suggestions.
[I asked a less clear version of this question here.]
I also probably need to use has many through because I will need the ability to destroy the relationship
Here's a solution using a self-referential relationship using single table inheritance. Use these commands to create the app:
$ rails myproject
$ cd myproject
$ script/generate model publication type:string name:string
$ script/generate model citation publication_id:integer reference_id:integer
The setup the relationships this way:
class Publication < ActiveRecord::Base
has_many :citations
has_many :cited_publications, :through => :citations, :source => :reference
has_many :references, :foreign_key => "reference_id", :class_name => "Citation"
has_many :refered_publications, :through => :references, :source => :publication
end
class Citation < ActiveRecord::Base
belongs_to :publication
belongs_to :reference, :class_name => "Publication"
end
class Article < Publication
end
class Book < Publication
end
class Chapter < Publication
end
Now we can create the DB and try it out from the console:
$ rake db:migrate
$ script/console
Loading development environment (Rails 2.2.2)
>> a = Article.create!(:name => "Article")
=> #<Article id: 1, ...>
>> b = Book.create!(:name => "Book")
=> #<Book id: 2, ...>
>> a.citations.create(:reference => b)
=> #<Citation id: 1, publication_id: 1, reference_id: 2, created_at: "2009-02-15 14:13:15", updated_at: "2009-02-15 14:13:15">
>> a.citations
=> [#<Citation id: 1, ...>]
>> a.references
=> []
>> b.citations
=> []
>> b.references
=> [#<Citation id: 1, publication_id: 1, reference_id: 2, created_at: "2009-02-15 14:13:15", updated_at: "2009-02-15 14:13:15">]
>> a.cited_publications
=> [#<Book id: 2, type: "Book", name: "Book", created_at: "2009-02-15 14:11:00", updated_at: "2009-02-15 14:11:00">]
>> a.refered_publications
=> []
>> b.cited_publications
=> []
>> b.refered_publications
=> [#<Article id: 1, type: "Article", name: "Article", created_at: "2009-02-15 14:10:51", updated_at: "2009-02-15 14:10:51">]
Here's a solution that doesn't use Single Table Inheritance for the publications. That means that there are articles, books and chapters tables, instead of one publications table. Here are the commands to run to create the app:
$ rails myproject
$ cd myproject
$ script/generate model book name:string
$ script/generate model chapter name:string
$ script/generate model article name:string
$ script/generate model citation publication_type:string publication_id:integer reference_type:string reference_id:integer
Create this file in lib/acts_as_publication.rb:
module ActsAsPublication
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_publication
has_many :citations, :as => :publication
has_many :references, :as => :reference, :class_name => "Citation"
end
end
end
Create this file in config/initializers/acts_as_publication.rb:
ActiveRecord::Base.send(:include, ActsAsPublication)
Then call that in each model, Article, Book and Chapter, like this:
class Article < ActiveRecord::Base
acts_as_publication
end
Then add these relationships in app/models/citation.rb:
class Citation < ActiveRecord::Base
belongs_to :publication, :polymorphic => true
belongs_to :reference, :polymorphic => true
end
Now we can create the DB and try it out from the console:
$ rake db:migrate
$ script/console
Loading development environment (Rails 2.2.2)
>> a = Article.create!(:name => "a")
=> #<Article id: 1, ...>
>> b = Article.create!(:name => "b")
=> #<Article id: 2, ...>
>> Citation.create!(:publication => a, :reference => b)
=> #<Citation id: 1, publication_type: "Article", publication_id: 1, reference_type: "Article", reference_id: 2, created_at: "2009-02-15 13:14:27", updated_at: "2009-02-15 13:14:27">
>> a.citations
=> [#<Citation id: 1, ...>]
>> a.references
=> []
>> b.citations
=> []
>> b.references
=> [#<Citation id: 1, ...>]
>> Book.create!(:name => "foo")
=> #<Book id: 1, name: "foo", created_at: "2009-02-15 13:18:23", updated_at: "2009-02-15 13:18:23">
>> a.citations.create(:reference => Book.first)
=> #<Citation id: 2, publication_type: "Article", publication_id: 1, reference_type: "Book", reference_id: 1, created_at: "2009-02-15 13:18:52", updated_at: "2009-02-15 13:18:52">
>> Book.first.references
=> [#<Citation id: 2, ...>]
>> a.citations
=> [#<Citation id: 1, publication_type: "Article", publication_id: 1, reference_type: "Article", reference_id: 2, created_at: "2009-02-15 13:14:27", updated_at: "2009-02-15 13:14:27">, #<Citation id: 2, publication_type: "Article", publication_id: 1, reference_type: "Book", reference_id: 1, created_at: "2009-02-15 13:18:52", updated_at: "2009-02-15 13:18:52">]
I have an incomplete answer over at http://github.com/francois/so-536261/tree/master
Basically, the DB schema does support your use case, but ActiveRecord doesn't. The solution will probably involve using find by sql or other tricks.