Today, I had a bug crop up in our Ruby-on-Rails application.
Somehow, the awsaccount_id field of our Device model is getting "marked for change" whenever we access the awsvpc association through the Device model.
To debug the problem, I added several log entries and several extra lines of code (as seen below) to diagnose how the device model instance is getting marked for change.
You may notice that the "dev.changes" method returns a pending change between logging "changes12" and "changes2". The only code that occurs between those log entries is accessing the association with dev.awsvpc.id
Under what circumstances can this ruby code:
Rails.logger.info "Update_Device changes0: #{dev.changes}"
sample_vpc = dev.awsvpc_id
Rails.logger.info "Update_Device changes1: #{dev.changes}"
sample_vpc = Awsvpc.find(dev.awsvpc_id)
Rails.logger.info "Update_Device changes12: #{dev.changes}"
sample_vpc = dev.awsvpc.id
Rails.logger.info "Update_Device changes2: #{dev.changes}"
Cause log entries that look like this:
Update_Device changes0: {}
Update_Device changes1: {}
[1m[36mAwsvpc Load (0.2ms)[0m [1m[34mSELECT "awsvpcs".* FROM "awsvpcs" WHERE "awsvpcs"."id" = $1 LIMIT $2[0m [["id", 644], ["LIMIT", 1]]
↳ app/lib/api/api_get_asset_result_builder.rb:53:in `populate_awssubnet'
Update_Device changes12: {}
[1m[36mCACHE Awsvpc Load (0.0ms)[0m [1m[34mSELECT "awsvpcs".* FROM "awsvpcs" WHERE "awsvpcs"."id" = $1 LIMIT $2[0m [["id", 644], ["LIMIT", 1]]
↳ app/lib/api/api_get_asset_result_builder.rb:55:in `populate_awssubnet'
Update_Device changes2: {"awsaccount_id"=>[66, 644]}
For anyone else who has this problem, I found the problem.
In the models, we had:
Device.rb
belongs_to :awsaccount, inverse_of: :devices, optional: true
belongs_to :awsvpc, inverse_of: :devices, optional: true
Awsvpc.rb
has_many :devices, :class_name => 'Device', dependent: :nullify, inverse_of: :awsaccount
Awsaccount.rb
has_many :devices, :class_name => 'Device', dependent: :nullify, inverse_of: :awsaccount
As you can see, the Awsvpc model should have used inverse_of :awsvpc
Once changed, everything works as expected.
Related
I have a web app in which I have the following relationship between two tables, a Topics and Categories table in which a Category has many Topics and a Topic belongs to a Category.
class Topic < ActiveRecord::Base
has_many :comments, dependent: :destroy
belongs_to :category
belongs_to :user
validates :subject, :body, :user_id, :category_id, presence: true
private
def self.find_by_id(params)
if params[:topic_id]
find(params[:topic_id])
else
find(params[:id])
end
end
def self.build_topic_comment(params, comment_params)
#topic = Topic.find_by_id(params)
#topic.comments.build(comment_params)
end
def self.load_comments(topic)
topic.comments.build
end
end
class Category < ActiveRecord::Base
has_many :topics, dependent: :destroy
belongs_to :user
validates :name, :user_id, presence: true
private
def self.find_by_id(params)
if params[:category_id]
find(params[:category_id])
else
find(params[:id])
end
end
def self.load_topics_desc(category)
category.topics.order(created_at: :desc)
end
def self.build_category_topic(params, topic_params)
#category = Category.find_by_id(params)
#category.topics.build(topic_params)
end
end
I added the functionality to move a topic to a different category by updating a topic's foreign key called category id. This is done trough an admin panel I coded myself and it is working correctly. When I checked the topics index page he category column is indeed updated.
The issue is that the rspec test I created is failing and giving me the following error:
Admin::TopicsController with administrator access PATCH #update with valid attributes updates a topic
Failure/Error: if #topic.update(topic_params)
ActiveRecord::InvalidForeignKey:
PG::ForeignKeyViolation: ERROR: insert or update on table "topics" violates foreign key constraint "fk_rails_d5d593e6f0"
DETAIL: Key (category_id)=(3) is not present in table "categories".
: UPDATE "topics" SET "subject" = $1, "body" = $2, "category_id" = $3, "updated_at" = $4 WHERE "topics"."id" = $5
# ./app/controllers/admin/topics_controller.rb:19:in `update'
# /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:19:in `block in process'
# /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:75:in `catch'
# /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:75:in `_catch_warden'
# /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:19:in `process'
# ./spec/controllers/admin/topics_controller_spec.rb:79:in `block (5 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# PG::ForeignKeyViolation:
# ERROR: insert or update on table "topics" violates foreign key constraint "fk_rails_d5d593e6f0"
# DETAIL: Key (category_id)=(3) is not present in table "categories".
# ./app/controllers/admin/topics_controller.rb:19:in `update'
The rspec test file:
require 'rails_helper'
RSpec.describe Admin::TopicsController, type: :controller do
describe 'with administrator access' do
let(:valid_attributes) { attributes_for(:topic) }
let(:invalid_attributes) { attributes_for(:topic, category_id: nil) }
let(:updated_attributes) { attributes_for(:topic, category_id: 3) }
before(:each) do
#topic = create(:topic)
admin = create(:admin)
sign_in admin
end
describe 'GET #index' do
it 'renders the index template' do
get :index
expect(response).to render_template(:index)
end
it 'loads all the topics in the database' do
get :index
expect(assigns(:topics)).to eq([#topic])
end
end
describe 'GET #show' do
it 'renders the show template' do
get :show, id: #topic
expect(response).to render_template(:show)
end
it 'retrieves a topic from the database' do
get :show, id: #topic
expect(assigns(:topic)).to eq(#topic)
end
it 'loads the topics comments' do
topic = create(:topic_with_comments)
get :show, id: topic
expect(topic.comments.length).to eq(5)
end
end
describe 'GET #edit' do
it 'renders the edit template' do
get :edit, id: #topic
expect(response).to render_template(:edit)
end
it 'retrieves a topic from the database' do
get :edit, id: #topic
expect(assigns(:topic)).to eq(#topic)
end
end
describe 'PATCH #update' do
context 'with valid attributes' do
it 'finds a topic in the database' do
get :edit, id: #topic
expect(assigns(:topic)).to eq(#topic)
end
it 'updates a topic' do
patch :update, id: #topic, topic: updated_attributes
#topic.reload
expect(assigns(:topic)).to eq(3)
end
it 'redirects to admin topic path' do
patch :update, id: #topic, topic: updated_attributes
expect(response).to redirect_to(admin_topics_path)
end
end
context 'with invalid attributes' do
it 'does not update a topic'
it 're-renders the edit template'
end
end
describe 'GET #new' do
it 'renders the new template'
it 'creates a new topic'
end
describe 'PUT #create' do
context 'with valid attributes' do
it 'saves a topic in the database'
it 'redirects to created topic'
end
context 'without valid attributes' do
it 'does not save a topic in the database'
it 're-renders the new template'
end
end
describe 'DESTROY #delete' do
it 'finds a topic in the database'
it 'deletes a topic from the database'
it 'redirects to admin topics index'
end
end
end
The admin topics controller:
class Admin::TopicsController < Admin::BaseController
def index
#topics = Topic.all
end
def show
#topic = Topic.find_by_id(params)
end
def edit
#topic = Topic.find_by_id(params)
#topic_options = Topic.all.collect { |topic| [ topic.category.name, topic.category_id ] }.uniq
end
def update
#topic = Topic.find_by_id(params)
if #topic.update(topic_params)
redirect_to admin_topic_path(#topic), notice: 'Topic updated successfully'
else
render :edit
end
end
private
def topic_params
params.require(:topic).permit(:subject, :body, :category_id)
end
end
Can someone point me in the right direction in regards to why the tests could be failing and the app is working correctly?
Thanks!
Hi I followed the Sunil tutorial but I'm getting the following db error:
Completed 500 Internal Server Error in 11.2ms
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
Processing by Refinery::PagesController#home as HTML
Parameters: {"locale"=>:es}
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
ActionView::Template::Error (PG::UndefinedTable: ERROR:
relation "refinery_project_translations" does not exist
2014-12-29T14:14:46.684169+00:00 app[web.1]:
LINE 5: WHERE a.attrelid = '"refinery_project_translati...
2014-12-29T14:14:46.684177+00:00 app[web.1]:
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
Migration file:
class CreateProjectTranslations < ActiveRecord::Migration
def up
::Refinery::Projects::Project.create_translation_table!({:description => :string},
:migrate_data => true)
remove_column :refinery_projects, :description
end
def self.down
add_column :refinery_projects, :description, :string
::Refinery::Projects::Project.drop_translation_table! :migrate_data => true
end
end
after running the migration the I realize is not not creating the the translation table for projects.
Model:
module Refinery
module Projects
class Project < Refinery::Core::BaseModel
self.table_name = 'refinery_projects'
translates :description
attr_accessible :name, :description, :date_started, :date_conclusion,
:position, :relevance, :img_id, :project_id, :status
validates :name, :presence => true, :uniqueness => true
has_many :project_images
has_many_page_images
class Translation
attr_accessible :locale
end
end
end
end
what I'm I missing here?
I solved this issue moving the migration file from the extension to the app migration folder. After that the application was able to create the table for the translation.
Below is a command to generate the extension. If to use it on an existing one, it`ll add all required code to already existing files by overriding them. Be careful with that - commit files before.
rails g refinery:engine Service title:string description:text icon:image --i18n title description
I'm currently experiencing an issue with the latest version of CanCan. It seems that the gem won't load singleton resources with pluralized names.
class Preferences < ActiveRecord::Base
self.table_name = 'preferences'
belongs_to :user
end
class User < ActiveRecord::Base
has_one :preferences
end
#controller
class PreferencesController < ApplicationController
before_filter :authenticate_user! #from Devise
load_and_authorize_resource :singleton => true,
:through => :current_user,
:through_association => :preferences,
:parent => false
end
#ability.rb
class Ability
include CanCan::Ability
def initialize(user)
can [:read, :update], Preferences, :user_id => user.id
end
end
I keep getting an error like this when I run my controller spec:
Failures:
1) PreferencesController GET #show should return http success
Failure/Error: get :show
NameError:
uninitialized constant Preference
# ./spec/controllers/preferences_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
It seems no matter what combination of load_resource arguments I try, I can't get my specs to pass again without reverting back to loading the resource manually like this:
class PreferencesController < ApplicationController
before_filter :authenticate_user!
def show
#preferences = current_user.preferences
authorize! :read, #preferences
end
end
Is there some magic combination of load_and_authorize_resource parameters I need to use? I have this same configuration working in another singleton controller where the resource falls under normal Rails conventions (i.e. User has_one :profile), so I know this works already under normal situations.
I'm a newbie and I got some trouble when run rails 3 server with mongodb (using mongoid) in production mode. Everything is ok in development mode, and I cannot figure out what am I missing. Please help me, thank you very much. This is the error:
ActionView::Template::Error (undefined method `map' for nil:NilClass):
2: #control{:style => "float: left;"}
3: %h3= t(:manage_shop)
4: =# debugger
=###### Already checking #shops variable but still got error ######
5: = hidden_field_tag :shop_list, #shops.blank? ? "test" : #shops.to_json
6: = form_tag("/shop", :method => "POST", :id => "frm_create_shop") do
7: %table
8: %tr
app/views/shop/index.html.haml:5:in`_app_views_shop_index_html_haml___1855911541554609468_28040500'
this is my action:
def index
#shops = Shop.all
respond_to do |format|
format.html
end
end
my model:
class Shop
include Mongoid::Document
include Mongoid::Geospatial
field :id, type: Integer
field :name, type: String
field :position, type: Point, :spatial => true, :delegate => true
spatial_scope :position
end
and my production.rb configuration:
Trunk::Application.configure do
config.cache_classes = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.serve_static_assets = false
config.assets.compress = true
config.assets.compile = false
config.assets.digest = true
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
end
And the second thing is I cannot get anything from db although everything is work well in development mode. If you have any suggestion, please help, thanks.
I'm having a strange problem when trying to set a callback for Facebook Authentication via Omniauth. In my controller (simplified to just the code necessary to show the error) I have:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
raise env.inspect
# auth_hash = env["omniauth.auth"]
end
end
this works in production mode, showing me the hash. However in test mode env is set to nil.
I have the following set in my spec_helper.rb file
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:facebook, {"credentials" => {
"token" => "foo-token"
}
})
and my spec looks like this:
require 'spec_helper'
describe Users::OmniauthCallbacksController do
describe "Facebook" do
before(:each) do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should be a redirect" do
get :facebook
response.should redirect_to(root_path)
end
end
end
Can anyone enlighten me on what I need to do to have env not be nil when running my tests?
I use the following in my spec_helper.rb :
RACK_ENV = ENV['ENVIRONMENT'] ||= 'test'
I don't use Rails or Devise though so YMMV. I've also seen various threads saying that someone had to do this before their requires to get it to work.