Rails 3 inherited_resources ignores 'defaults' setting - ruby-on-rails-3

I'm using Inherited resources for my controllers. And now i have model:
class Sms < ActiveRecord::Base
end
And i want controller for it, where i make defaults:
class Admin::SmsesController < Admin::InheritedResources
defaults :resource_class => Sms,
:collection_name => 'smses',
:instance_name => 'sms'
end
but i can not understand, why it still trying to get "Smse" model:
NameError in Admin::SmsesController#index
uninitialized constant Smse
Pls help.

The problem is that Rails doesn't know that the plural of Sms is Smses. If you go to the Rails console you should see that:
> "Sms".pluralize
=> "Sms"
> "Smses".singularize
=> "Smse"
When faced with a plural it doesn't recognise, singularize just truncates the final "s", which is why your app is looking for a nonexistent Smse model.
You will save yourself a lot of headaches by configuring Rails to pluralize/singularize your models correctly. In the file config\initializers\inflections.rb you should find some examples of how to do this. What you want is:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'sms', 'smses'
end
Then I don't think you should need to put the defaults option in there at all - it should all work out of the box.

Related

Devise sign_in_params method missing

I'm attempting to use Devise (2.2.4), which I'm new to, with the Rails 3.2.13/Ruby 2.0.0p195 app I'm building. I turned scoped_views on because I want to have my own separate users and admins views. And I created my own Users::RegistrationsController which seems to be doing what I want it to. I've just added my own Users::SessionsController, which is where I've hit problems.
I straight copied over a couple of action methods from the Devise::SessionsController source as a first step, planning to modify them once they were working (my controller code is at the bottom of this post). But my 'new' method is failing, when called, with a NameError because `sign_in_params' is apparently undefined.
Well, that seems pretty strange because I'm inheriting from Devise::SessionsController, and when I look at the source for that on GitHub, there's the sign_in_params defined in the protected section at the bottom. So I decided to investigate whether my controller is inheriting correctly from Devise::SessionsController - and it certainly seem to be. I can list out all the inherited methods, just not that one missing one. So I ended up running the following piece of code in the Rails Console:
(Devise::SessionsController.new.methods - DeviseController.new.methods).each {|m| puts m}
And it produces the following output:
_one_time_conditions_valid_68?
_one_time_conditions_valid_72?
_callback_before_75
_one_time_conditions_valid_76?
new
create
destroy
serialize_options
auth_options
If I ignore the underscored methods, the remainder are all those methods defined in the Devise::SessionsController source except sign_in_params. I can't see how anything I've written can be deleting that method, and I can't think what else to try. Google is silent on this problem, so I assume I'm doing something uniquely foolish, but I can't work out what. Any suggestions please? And might someone else try running that bit of Rails Console code to see what they get?
class Users::SessionsController < Devise::SessionsController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
prepend_before_filter :allow_params_authentication!, :only => :create
prepend_before_filter { request.env["devise.skip_timeout"] = true }
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
I think you are using code from a devise version compatible with Rails 4 on a rails 3 application.
sign_in_params is a method to be used with strong parameters. A gem used in rails 4.
If you check the controller on devise version 2.2. https://github.com/plataformatec/devise/blob/v2.2/app/controllers/devise/sessions_controller.rb
You will see that there is no sign_in_params method.
Check which version of devise you are using and copy the code based on that devise version in your controller, rather than the latest code from github.

How can you make sure a username won't conflict with an existing route?

So I'd like to have urls on my site like http://foobar.com/hadees that goes to someone's profile. However when registering usernames how do I make sure they don't pick something that will conflict with my existing routes?
I'm guessing I need to get a list of the existing routes but I'm not sure how to do it.
A short google search gives me that:
http://henrik.nyh.se/2008/10/validating-slugs-against-existing-routes-in-rails
In rails 3 the method has moved to Rails.application.routes.recognize_path
So I summarize :
class User < ActiveRecord::Base
validates_format_of :name, :with => /\A[\w-]+\Z/
validates_uniqueness_of :name
validate :name_is_not_a_route
protected
def name_is_not_a_route
path = Rails.application.routes.recognize_path("/#{name}", :method => :get) rescue nil
errors.add(:name, "conflicts with existing path (/#{name})") if path && !path[:username]
end
end
Good question. Through a little tinkering, I found that you can get the routes in your app via:
Rails.application.routes.routes.collect{|r| r.path}

Redirecting from a namespaced controller using a hash

I have a double namespace situation, where my controllers look like this:
CandidateController
Candidate::PerformanceController
Candidate::Performance::ReviewController
In Rails 2, I was able to use redirect_to from the Candidate::Performance::ReviewController controller in order to redirect to an action in the CandidateController, like so:
class Candidate::Performance::ReviewController < ApplicationController
before_filter :ensure_manager
# ...
def ensure_manager
if !current_user.manager?
flash[:warning] = t(:must_be_manager)
redirect_to :controller => '/candidate', :action => :index
end
end
end
The / in controller => '/candidate' would allow Rails to redirect from app.com/performance/reviews to app.com/candidate.
However, this seems to not work the same in Rails 3.1. Instead, my redirect_to goes to app.com/candidate//candidate. What is the correct way to specify a "absolute" controller within a redirect_to hash (ie. without using a path helper)?
Update: I know this would be infinitely easier if I just use named route helpers (ie. candidate_path). Unfortunately, there is a lot of legacy code in our codebase which doesn't use RESTful routing and instead uses the default "catch-all" route; ie. we have a lot of actions with no named route to fallback on.
I wonder if something else is wrong. In the doc:
In particular, a leading slash ensures no namespace is assumed. Thus,
while url_for :controller => ‘users‘ may resolve to
Admin::UsersController if the current controller lives under that
module, url_for :controller => ’/users‘ ensures you link to
::UsersController no matter what.
And I don't think it changed...
Also, shouldn't the catch-all routes be after the default routes in your config?
I think that redirect_to :controller => ... uses url_for to build the url, so in the end, if your custom routes catches /candidates, I don't really see the difference.
Some people have the same problem: https://github.com/rails/rails/issues/2575
Patching actionpack/lib/action_dispatch/routing/route_set.rb line 434
as follows fixes this: if !named_route && different_controller? &&
!controller.starts_with?('/')
If anyone else runs into this problem, it seems to be a known issue (unsure whether they consider it a bug or not, given the lack of response on the issue page from anyone working on Rails).
Until they patch it (assuming they do), I've added the following little monkey patch into an initializer, based on the code given in the original post of that issue:
module ActionDispatch
module Routing
class RouteSet
class Generator
def use_relative_controller_with_absolute_paths!
return if controller.starts_with?('/')
use_relative_controller_without_absolute_paths!
end
alias_method_chain :use_relative_controller!, :absolute_paths
end
end
end
end
Hope this can help someone else!
Update: It seems that this was fixed in Rails here.

Mongomapper: Embedded document does not work properly

I don't know what's going on but I can't seem to find working a very small piece of code. I used mongomappper without embedded documents and everything went fine. Using an embedded document I hit the brick wall. I'm following the instructions on the mongomapper homepage using the Rails console:
Here are my models:
class Assessment
include Mongomapper::Document
many :sections
end
class Section
include MongoMapper::EmbeddedDocument
key :title, String
validates_presence_of :title
end
When I run:
a = Assessment.create(:sections => [ Section.new(:title => 'test') ] )
I will get the following output:
=> #<Assessment _id: BSON::ObjectId('4e71efce69a74c0fb6000002'), sections: nil>
I also tried with a = Assessment.new(), a.sections << Section.new(:title => "test")
but the same result.
Why is there nothing inside sections?
Including:
attr_accessible :sections
should make the create work (at it does for me). And you'll probably want to add:
validates_associated :sections
to make your Assessment validate the embedded Sections the way you'd probably expect.
Yeah, a couple years late but I just had to sort this problem out and Google brought me here.

Rails 3 Custom Validator Problem

I need to apply validation to a Model so that 2 integer values in the record, minimum and maximum, form an inclusive range (ex. 2 and 3 are ok, but 4 and 1 are not). From what I understand, since I need to validate 2 values against each other in the same record, I have to use ActiveModel::Validator (and not ActiveModel::EachValidator). So, I try the following:
Model (app/models/position.rb):
class Position < ActiveRecord::Base
validates_with InclusiveRangeValidator
end
Validator (app/lib/validators/inclusive_range_validator.rb):
class InclusiveRangeValidator < ActiveModel::Validator
def validate(record)
record.errors[:base] << "#{record.minimum} and #{record.maximum} do not form a valid inclusive range." unless record.minimum < record.maximum
end
end
I've read that Rails 3.0.5 doesn't automatically load the lib directory anymore, so I added this line in config/application.rb:
config.autoload_path += %W({config.root}/lib)
And then I reset the rails server so it'll take the change to config/application.rb. I run my unit tests, which tries to exercise the model to prove this validation works. I get this error:
uninitialized constant: Position::InclusiveRangeValidator (NameError)
What I think is happening is that Rails is not recognizing/finding my custom validator class, and so it assumes InclusiveRangeValidator is a constant in the class that it's referenced in. But, I thought the change I made to config/application.rb would put my validator in the load path so that it would be available.
I've gone through the other posts on StackOverflow and didn't come up with a solution, and I've read the API docs on validators, to no avail. I've got to be doing something simple and stupid, but I can't see what the issue is. Any help?
EDIT:
After more searching, I discovered that I don't need a custom validator at all, as I can accomplish the same goal with this:
validates :minimum, :numericality => {:greater_than_or_equal_to => 0 }
validates :maximum, :numericality => {:greater_than => :minimum }
However, the question still remains as to why Rails can't locate the custom validation class.
Once, I changed the line in application.rb to:
config.autoload_paths += %W[#{config.root}/lib/validators/]
Rails was able to find the right path to load my custom validator. I made the mistake of assuming Rails would automatically recurse the directory structure, this is evidently not the case.