I'm using rails 2.3.5 and ruby 1.8.7. I'm building a simple TODO manager. Where I have tasks that belong to a user and a user has many tasks.
I'm using acts_as_taggable_on_steroids plugin for tagging tasks and restful_authentication plugin for registration and user management.
I'm getting a weird error that reads "Can't dup NilClass" on the view of index action. This is what the controller code is -
#tasks = current_user.tasks
The error occurs when I'm iterating over #tasks on the view. That is when I do #tasks.each do |task|
Now when I replace the controller code with this
#tasks = Task.find(:all, :conditions => {:user_id => current_user.id})
Which is actually fetching the same records. This happen only in development mode. I am guessing this has something to do with caching or loading.
What could be wrong? I'm facing this issue for the first time.
EDIT
Okay, this is definitely a caching issue. If I make
config.cache_classes = true in production.rb, the same error occurs in production mode as well. But how do I fix that now? Because I don't want to be reloading the server for every change I make in models/controllers.
EDIT
Here is how my User model looks like
class User < ActiveRecord::Base
has_many :tasks
has_many :projects
# There are some validations and standard methods that resful authentication
# provides that I am not showing here
end
And this is how the Task model looks like.
class Task < ActiveRecord::Base
belongs_to :bin
belongs_to :project
belongs_to :user
acts_as_taggable
def tag_list
super.join(', ')
end
end
Task controller's index method looks like this
def index
#tasks = current_user.tasks
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #tasks }
end
end
Hope this helps.
Got it.
From here,
Some of the classes inherited or
included in your engine controllers
may fail to get unloaded and cause
trouble after the first request to
your system.
For me, it was because I had a file in the lib that was monkey patching User model and the
User model class in this file was not getting cached I suppose.
Calling unloadable in that class in the lib folder did the trick. So my lib file looks like this
class User < ActiveRecord::Base
unloadable
# stuff...
end
Thanks anyways.
Maybe there is something wrong with associations in model. Can you paste some code from there?
You can also try doing the same in console. Does it give the same error? Take a look in logs, do both of your examples generates the same sql query?
Related
first time asking a question on stack overflow :)
I'm having a conflict between friendly_id and active admin (it's an assumption), as discussed in many threads here. I've looked at all those threads, but I'm not entirely sure they solve my problem. Sorry for the really long post!
I'm trying to create friendly links to products on my website. I've added the friendly_id gem and everything works fine in my dev and staging environments, but friendly links fail on production. Here is all my code:
Model:
class Product < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
...
end
Controller:
class ProductsController < ApplicationController
before_filter :get_product, only: [:show]
...
private
def get_product
#product = Product.friendly.find(params[:id])
end
end
All my product records have a completed slug field at this point. I don't want to use slugs in my admin interface, so when I came across a solution here, I went ahead and modified it a bit to get active admin to work together with friendly_id.
config/initializers/active_admin.rb:
ActiveAdmin.setup do |config|
...
config.before_filter :revert_friendly_id
end
I've defined revert_friendly_id in the application controller:
class ApplicationController < ActionController::Base
...
protected
def revert_friendly_id
model_name = self.class.name.match(/::(.*)Controller$/)[1].singularize
# Will throw a NameError if the class does not exist
Module.const_get model_name
eval(model_name).class_eval do
def to_param
id.to_s
end
end
rescue NameError
end
end
I've noticed that when I first deploy to production via capistrano, the friendly links work as expected. So my product links are accessible with: http://website.com/products/my-product-slug. But the minute I access the admin interface on production, the links immediately switch back to product ids instead: http://website.com/products/12345. I'm not entirely sure how to resolve this problem, though I understand why it might be happening, can someone help me please?
Here is how I solved the problem. Based on armstrjare's fix at this link.
I removed the revert_friendly_id function from my application controller and the before_filter from my config. Then just added the following to app/admin/product.rb:
ActiveAdmin.register Product do
around_filter do |controller, action|
Product.class_eval do
alias :__active_admin_to_param :to_param
def to_param() id.to_s end
end
begin
action.call
ensure
Product.class_eval do
alias :to_param :__active_admin_to_param
end
end
end
...
end
And everything worked as expected. Hope this helps someone else!
I found a very simple solution: Just overwrite the to_param in your model and check if it is called from active_admin.
app/models/product.rb:
class Product < ActiveRecord::Base
def to_param
if caller.to_s.include?"active_admin"
id && id.to_s
else
slug
end
end
end
When you set the to_param method, it will be set on the entire application. So you have to check if the requested controller is in the Admin namespace or not. Based on that you have to switch back the return of the to_param method.
You can redefine find_resource method in controller:
controller do
def find_resource
scoped_collection.friendly.find(params[:id])
end
end
For the active_admin belongs_to association you can to use the finder: option (from https://github.com/activeadmin/inherited_resources/blob/master/lib/inherited_resources/belongs_to_helpers.rb#L17)
For example:
belongs_to :content, finder: :find_by_slug!
My background
I am/was a PHP developper. Have been for 15 years. Ruby is new to me (My new challenge)!
Current Setup
I am using Devise with a User model.
Rails: 3.2.1
Devise: 2.1.2
Use Case
When the user registers (going thru Devise controller), I want to create the User record but also a Foo record automatically. I created an after_create which handles the creation of the Foo record.
Class User < ActiveRecord::Base
after_create :make_foo
def make_foo
Foo.create(
:name => name,
:user_id => id
)
end
end
Class Foo < ActiveRecord::Base
belongs_to :user
end
Symptoms
I had a problem where when the Foo record was not being created (validation for example), then the User record was still created (I did not want that). I added a Raise Exception in after_create which rolls back the User creation.
However, I would prefer some nice error handling rather than Exception being throwed. Right now I get a 500 Error page with that Exception.
I would prefer that the form can be shown again with the reason(s) of the failure.
Class User < ActiveRecord::Base
after_create :make_foo
def make_foo
foo = Foo.create(
:name => name,
:user_id => id
)
if !foo.valid?
raise Exception.new('Foo creation failed.')
end
end
end
Plea for help
Any suggestions?
Instead of raising an exception you can redirect back to same page with setting flash message in
if !foo.valid?
block like this
flash[:error] = 'error msg'
and redirect using
session[:return_to] = request.referer
redirect_to session[:return_to]
I ended up overriding the Devise Resitrations Controller and putting a begin...rescue...end inside the create method.
# routes.rb
devise_for :users, :controllers => { :registrations => "my_devise/registrations" }
# app/controllers/my_devise/registrations_controller.rb
class MyDevise::RegistrationsController < Devise::RegistrationsController
def create
begin
super
rescue Exception
self.resource.errors[:base] << "My error message here"
clean_up_passwords resource
respond_with resource
end
end
end
You might want to look at Rails3: Devise User has_one relationship to see if better modelling can make the problem easier.
The way you are modelling user.rb now, is indeed such that a User may exist without Foo (which must belong to a User however), so it just calls :make_foo as an after_create callback with no other guarantees whatsoever.
I've a field in my database called IP where I put the user IP (in #create method) when he send a message in my blog built in Rails.
But the field is visible when I want to see the articles in another format (JSON).
How can I hide the field IP?
You can do it in a format block in your controller like this:
respond_to do |format|
format.json { render :json => #user, :except=> [:ip] } # or without format block: #user.to_json(:except => :ip)
end
If you want to generally exclude specific fields, just overwrite the to_json method in your user model:
class User < ActiveRecord::Base
def to_json(options={})
options[:except] ||= [:ip]
super(options)
end
end
Update: In Rails 6, the method became as_json:
class User < ApplicationRecord
def as_json(options={})
options[:except] ||= [:ip]
super(options)
end
end
While this is not quite the right solution for passwords or for what is specifically asked, this is what comes up when you google for hiding columns in ActiveRecord, so I'm going to put this here.
Rails5 introduced new API, ignored_columns, that can make activerecord ignore that a column exists entirely. Which is what I actually wanted, and many others arriving here via Google probably do too.
I haven't tried it yet myself.
class User < ApplicationRecord
self.ignored_columns = %w(employee_email)
end
https://blog.bigbinary.com/2016/05/24/rails-5-adds-active-record-ignored-columns.html
I'm having an issue coming up with a good way to do the following. I have a very generic Org model and User model. Org has_many :users, and User belongs_to :org.
I am trying to find a way of showing a list of users that is not restricted by Org, but also show a list of User's that is restricted by Org. I know I could nest the routes, and just have two different routes like
map.resources :users
map.resources :orgs, :has_many => :users
The problem is that they both go back to the same actions in the User controller. The controller code starts to get very messy because I am having to check for the existence of an :org_id param. Then I have to decide whether to return the normal results of a find call on User, or a find that is scoped to an Org. I'm not sure what the best solution is here, or what the best practice is. If someone with some knowledge on this could please enlighten me, it would be great.
Another way of doing this without a plugin would be to use named_scope. You can create a named scope in User that filters by org_id if it's not empty.
class User < ActiveRecord::Base
belongs_to :org
named_scope :by_org, lambda{|org| org.blank? ? {} : { :conditions => ['org_id = ?', org] }}
end
And in the controller just use your named scope. That way if you eventually supply more filter options in the controller you don't need to duplicate them:
class UsersController < ApplicationController
def index
#users = User.by_org(params[:org_id]).all
...
end
end
Not really the answer you were probably looking for on a technical level but I use a plugin for my projects that takes care of that mess for me. Take a look at make_resourceful.
make_resourceful do
actions :all
belongs_to :org
end
It will figure out the rest for you, no need to define your standard crud action. It will even detect scoping and scope it for you. (unless that's an other plugin i'm using I forgot about)
I use resource_controller plugin for most cases. With it, you just put:
class UsersController < ApplicationController
resource_controller
belongs_to :org
end
It works with nested and not-nested resources.
If you don't want to use additional plugin, your controller still won't be very complicated.
class UsersController < ApplicationController
def index
#org = Org.find(params[:org_id]) unless params[:org_id].blank?
#users = params[:org_id].blank? ? User.all : #org.users
...
end
end
What I usually do is this:
class UsersController < ApplicationController
def index
root = Org.find(params[:org_id]) if params[:org_id]
root = User if root.nil?
#users = root.all(:conditions => {...}, :order => "...")
end
end
I'm basically doing a tree-walk. As conditions are added, I simply change the root of the #find call. When I'm done evaluating conditions, I call the final #find / #first / #all method and I'm done.
This also works if you have multiple named scopes:
class UsersController < ApplicationController
def index
root = Org.find(params[:org_id]) if params[:org_id]
root = User if root.nil?
root = root.named(params[:name]) if params[:name]
root = root.registered_after(params[:registered_at]) if params[:registered_at]
# more conditions, as required
#users = root.all(:conditions => {...}, :order => "...")
end
end
In my Ruby on Rails app, I've got:
class AdminController < ApplicationController
def create
if request.post? and params[:role_data]
parse_role_data(params[:role_data])
end
end
end
and also
module AdminHelper
def parse_role_data(roledata)
...
end
end
Yet I get an error saying parse_role_data is not defined. What am I doing wrong?
Helpers are mostly used for complex output-related tasks, like making a HTML table for calendar out of a list of dates. Anything related to the business rules like parsing a file should go in the associated model, a possible example below:
class Admin < ActiveRecord::Base
def self.parse_role_data(roledata)
...
end
end
#Call in your controller like this
Admin.parse_role_data(roledata)
Also look into using (RESTful routes or the :conditions option)[http://api.rubyonrails.org/classes/ActionController/Routing.html] when making routes, instead of checking for request.post? in your controller.
Shouldn't you be accessing the parse_role_data through the AdminHelper?
Update 1: check this
http://www.johnyerhot.com/2008/01/10/rails-using-helpers-in-you-controller/
From the looks of if you're trying to create a UI for adding roles to users. I'm going to assume you have a UsersController already, so I would suggest adding a Role model and a RolesController. In your routes.rb you'd do something like:
map.resources :users do |u|
u.resources :roles
end
This will allow you to have a route like:
/users/3/roles
In your RolesController you'd do something like:
def create
#user = User.find_by_username(params[:user_id])
#role = #user.roles.build(params[:role])
if #role.valid?
#role.save!
redirect_to #user
else
render :action => 'new'
end
end
This will take the role params data from the form displayed in the new action and create a new role model for this user. Hopefully this is a good starting point for you.