From Padrino to Rails 3.2 - skinny controllers - ruby-on-rails-3

I'm slightly lost in Rails 3.2. I've used to create skinny controllers in Padrino using methods like this:
15 post :task, :provides => :js do
16 result = execute(params)
17 render "home/task"
18 end
Some methods does not exactly interacts with a model. In Rails 3.2, I cannot use helpers in controllers to make them clean (like Rails 2.x or Padrino). I've created a few methods like this one:
10 def show
11 #server = server_details
12 respond_with(#server) if request_match_server_address?
13 end
But moved code from ServersController to ApplicationController, assuming it will be temporarily, and now application_controller is ugly and biggger (sure with three g's).
How can I make my controllers beauty? Where is the right place to put methods like server_details?

in routes.rb
post "/task", to: "tasks#show"
in tasks_controller.rb
respond_to :js
def show
#result = execute(params)
respond_with #result
end
this will automatically use the view tasks/show.js
good luck

montrealmike's answer is how you would translate your Padrino to Rails 3.
But to answer the question you asked (with the "?"),
you can use helpers in Rails 3, as there just normal ruby modules.
You just need to include them:
include ServerHelper
def show
#server = server_details
respond_with(#server) if request_match_server_address?
end
where you have app/helpers/server_helper.rb
module ServerHelper do
def server_details
...
end
def request_match_server_address?
...
end
end
Edit: You can also include them in the ApplicationController and they will be inherited like all other good little classes.

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.

Before filter in action mailer Rails 3

What I need:
Something similar to before_filter in ActionMailer in Rails 3.
Problem:
I am working on Rails 3 and want to have a before_filter in ActionMailer. Checked the actionmailer api and learned about before_action and after_action callbacks. When implemented it gives the error:
NoMethodError: undefined method `before_action' for Notifier:Class
Later learned that there is no before action call for Rails 3 from this post
Isnt there any hook or gem so that we can have something similar like before_filter in Rails 3.
Please help. Many Thanks!!
It can be achieved by including AbstractController::Callbacks. This mimics the change to Rails 4 which apart from comments and tests, just included Callbacks.
class MyMailer < ActionMailer::Base
include AbstractController::Callbacks
after_filter :check_email
def some_mail_action(user)
#user = user
...
end
private
def check_email
if #user.email.nil?
message.perform_deliveries = false
end
true
end
end
Reference - How to add a before_filter in UserMailer which checks if it is OK to mail a user?

REST Routes and overriding :id with to_param

My controller is using the default RESTful routes for creating, adding, editing etc
I want to change the default :id to use :guuid. So what I did was:
# routes.rb
resources :posts
# Post Model
class Post < ActiveRecord::Base
def to_param # overridden
guuid
end
end
This works but my modifed REST controller code has something like this
def show
#post = Post.find_by_guuid(params[:id])
#title = "Review"
respond_to do |format|
format.html # show.html.erb
end
end
When I see this this code ..
Post.find_by_guuid(params[:id])
it would seem wrong but it works.
I don't understand why I can't write it out like this:
Post.find_by_guuid(params[:guuid])
Why do I still have to pass in the params[:id] when I'm not using it?
Looking for feedback on whether my approach is correct or anything else to consider.
Even though it works it doesn't always mean it's right.
Type rake routes in your console, and check the output of the routes. You'll see the fragment ':id' in some of them, that's where the params[:id] comes from. It's a rails convention : when you use resources in your routes, the parameter is named id. I don't know if you can change it (while keeping resources; otherwise you could just go with matching rules), but you shouldn't anyway : even if it seems not very logic, it actually has sense, once your understand how rails routing works.

RoR 3.0.9 - Passing a variable from routes.rb to application_controller.rb or viceversa

I have a multi site project that changes from one to another by changing two variables, one is inside routes.rb and the other in application_controller.rb. Is it possible to pass variables between these files so that I only have to change a parameter to achieve the change required?
On my routes.rb file I use this variable to assign the correct controller the routes it should use. For example:
def showsite
"mysite1"
end
root :to => "#{showsite}#index"
And on application_controller.rb I use the same parameter to get the domain of the site, some layouts it should use and another things. For example:
before_filter :set_defaults
def showsite
"mysite1"
end
def set_defaults
if "#{showsite}" == "mysite1"
#domain = 'mysite1.com'
elsif "#{showsite}" == "mysite2"
#domain = 'mysite2.com'
else
#domain.nil?
end
end
def special_layout
"#{showsite}"
end
Every time I want to show a different version of the project I need to change two variables. I know its not a lot but I have to do it many times a day. Im pretty new on RoR, if there is a better solution please guide me to it. Thanks!
Why not use a Rails Initializer. E.g. the following:
File: `config/initializers/showsite.rb`
with the following content:
MyApp::Application.config.showsite = 'mysite1'
Then you should be able to use:
def showsite
MyApp::Application.config.showsite
end
and similar in your routes file.

Rspec 2 and Rails 3 stubbing / mocking

I am currently in the process of migration to rails 3 from rails 2 in a large application. In our functional specs, we have alot of stuff like this:
#model = Factory :model
#child = Factory :child
Model.stub!(:find).and_return(#model)
Child.stub!(:find).and_return(#child)
...
#child.should_receive(:method).twice
The main issue is that if I let it hit DB and get actual instance of child, real :method makes tests too complex (need two big factories) and slow.
In code we use various ways to get items: find, dynamic finders, etc
#model = Model.find(1)
#child = #model.children.find_by_name(name)
How would you advice to move this logic to rails 3? Any advice on another stubbing/mocking library maybe?
Normally you would mock the model inside controller specs:
Model.stub!(:find).and_return(mock_model('Model'))
Child.stub!(:find).and_return(mock_model('Child'))
However, when you've got gem "rspec-rails", "~> 2.0" in your rails 3 app's Gemfile, then the standard rails scaffold generator will use rspec to generate specs for you, so running rails generate scaffold MyResource will generate some example specs for you.
The following is a lightly annotated version of what rails/rspec will generate for controller specs, so I suppose this should be considered "The RSpec Way".
describe AccountsController do
# Helper method that returns a mocked version of the account model.
def mock_account(stubs={})
(#mock_account ||= mock_model(Account).as_null_object).tap do |account|
account.stub(stubs) unless stubs.empty?
end
end
describe "GET index" do
it "assigns all accounts as #accounts" do
# Pass a block to stub to specify the return value
Account.stub(:all) { [mock_account] }
get :index
# Assertions are also made against the mock
assigns(:accounts).should eq([mock_account])
end
end
describe "GET show" do
it "assigns the requested account as #account" do
Account.stub(:find).with("37") { mock_account }
get :show, :id => "37"
assigns(:account).should be(mock_account)
end
end
describe "GET new" do
it "assigns a new account as #account" do
Account.stub(:new) { mock_account }
get :new
assigns(:account).should be(mock_account)
end
end
end