How to short the Controller actions in Rails - ruby-on-rails-3

def index
#customers = current_user.customers
respond_to do |format|
format.html # index.html.erb
format.json { render json: #customers }
end
end
def show
#customer = current_user.customers.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #customer }
end
end
def new
#customer = current_user.customers.new
end
This is a little part of my CustomerController. The origin #customers was #customers = customers and so on.
I wanted to index/show/new just for the current_user. This is working, but i had to manually change all the Controller actions.
And also all my automated spec files are just testing for #customer = customers.
This seems not the rails way to change all of them manually.
Is there a better solution for this?
thanks in advance
best regards
denym

The Rails way to tackle this would be using the inherited_resources gem in combination with Responders. Exactly your use case is described in the Overwriting Defaults section of inherited_resources.
This approach is also discussed in the chapter "Writing DRY Controllers with Responders and Generators" in José Valims book Crafting Rails Applications: Expert Practices for Everyday Rails Development.

I think you are looking for a before_filter. Something like:
before_filter :valid_user, only: [:index, :new, :show]
def valid_user
redirect_to root_path if current_user.nil?
end

Related

Rails: code in model or controller

What is the best approach here? I'm trying to clean up some code and I'm wondering if the controller is the best place for this variety of logic:
if user_signed_in?
if current_user.try(:admin?)
#docs = Doc.chronologic.page(params[:page]).per(5)
#orders = Order.chronologic.page(params[:page]).per(5)
else
#docs = Doc.chronologic.where(:user_id => current_user.ftp, :retired => "active").page(params[:page]).per(5)
#orders = Order.chronologic.where(:user => current_user.ftp).page(params[:page]).per(5)
end
respond_to do |format|
format.html
format.json { render json: #docs }
end
else
redirect_to new_user_session_path
end
If there's a better location for it, where would it be?
Thanks!
Edit: it's far worse for methods like pdf which has line after line of instructions for Prawn, but I can't seem to get send_data to work from the model.
This is basically what mu said, but here's my take.
In your app controller:
def require_logged_in
redirect_to new_user_session_path unless user_signed_in?
end
In your controller
before_filter :require_logged_in
def some_action
#docs = Doc.chronologic.for_user(current_user).page(params[:page]).per(5)
#orders = Order.chronologic.for_user(current_user).page(params[:page]).per(5)
respond_to do |format|
format.html
format.json { render json: #docs }
end
end
In your Doc model
scope :for_user, lambda do |user|
where(:user_id => user.ftp, :retired => "active") unless user.admin?
end
And something similar in your Order model.
Per your edit, definitely don't do send_data from your model.

How can I manage public records and user specific records

I have a situation where a company is managed by a user. i.e.: A user can create, read, update and delete their own companies. But I'd also like that same user to access a list of all companies in the system, even when logged out.
e.g.:
user_a manages the following companies: company_a and company_b
user_b manages the following companies: company_c and company_d
user_a should be able to see a list of his own companies (a and b) as well as a list of all companies (a, b, c, and d)
What's the best way to handle this in the controllers?
Idealy, I'd like to have it setup under 2 separate routes as follows:
/companies
/users/1/companies
Should I have one controller for companies, or multiple? and how would that work?
I'm looking for best practices in this type of scenario.
In your situation approach can be:
Use Devise RubyGem to handle authentication. https://github.com/plataformatec/devise
Create or Scaffold simple CompaniesController with RESTful actions set: index, new, create, edit, udpate, destroy actions.
Add before_filter in CompaniesController to restrict access to action which require user authentication:
before_filter :authenticate_user!, :except => [:public_list]
You should have has_many assosiation between User and Company ActiveRecord models, to access companies collection of current_user.
Here goes example code:
Routing:
resources :users do
resources :companies
end
match '/companies' => 'companies#public_list', :as => :public_companies_list
Controller:
class CompaniesController < ApplicationController
before_filter :authenticate_user!, :except => [:public_list]
def index
#companies = current_user.companies
end
def show
#company = current_user.companies.find(params[:id])
end
def new
#company = current_user.companies.new
end
def edit
#company = current_user.companies.find(params[:id])
end
def create
#company = current_user.companies.new(params[:company])
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
else
format.html { render action: "new" }
end
end
end
def update
#company = current_user.companies.find(params[:id])
respond_to do |format|
if #company.update_attributes(params[:company])
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
def destroy
#company = current_user.companies.find(params[:id])
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url }
end
end
end
For public companies list add this method:
def public_list
#companies = Company.all
end
IMHO if all user can see all companies it's perfect to have one controller to get this job. Just in template you can check if current user is author of specified company and then add link to edit this company etc. if you want of course.

respond_with do not redirect to index.html.erb

I need help with the responder respond_with, 'cause when I create a new post (in this case) It doesn't redirect to the location specified. What can be?. This is the piece of my code that creates a new post but It's be redirected to create.html.erb and not the index.html.erb that I specified.
def create
#post = Post.create(params[:post])
respond_with(#post, :status => :created, :location => posts_url)
end
try to use "redirect_to" (from ACIIcasts - Controllers in Rails 3):
redirect_to #result, :notice => "Successfully converted original data."
If you are not confortable with the solution i found a workaround in a similar post: link
def convert
#result = Result.find(params[:id])
#result.convert_original_data
success = #result.save
respond_with(#result) do |format|
format.html {redirect_to result_path(#result) } if success
end
end
You don't need to supply location. It will do it automagically for you.
All you need to do is...
respond_with #post
It will set the correct status and redirect you to the posts_url.

Rails 3.1 respond_to :html with :except

I have the following in my controller:
respond_to :html, :except => :some_action
respond_to :json, :xml
If you hit the :some_action route in a browser (tested with Chrome), you get a 406 Not Acceptable response back. Is there a way to "catch" this in Rails and do something else (like a redirect)?
Additionally, I'm trying to avoid using the block form of respond_to. I'm just curious if there is some way to handle this case.
Check this out: http://ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
There's a bit about action overriding:
class UsersController < ApplicationController::Base
respond_to :html, :xml, :json
# Override html format since we want to redirect to a different page,
# not just serve back the new resource
def create
#user = User.create(params[:user])
respond_with(#user) do |format|
format.html { redirect_to users_path }
end
end
end

Rails3 and Respond_with problem

I have an application, on which I have two user interfaces.
The first one is for normal users and the second one is for iphone users.
Everything was working fine until i refactored my code within controller to use the respond_with declarative instead of respond_to.
The application is still working for the html interface(:format => :html) but not on the iphone interface(:format => :iphone).
On the iphone, when I do the following action (:index, :new, :edit, :show) it works.
But when i do (:create, :update, :destroy), I get errors saying the template is not found(create.iphone.haml for example).
On my controller I have
respond_to :html, :iphone
And then for example, the edit and the update action
def edit
#refund = Refund.find(params[:id])
respond_with(#refund)
end
def update
#refund = Refund.find(params[:id])
if #refund.update_attributes(params[:refund])
flash[:notice] = 'Refund was successfully updated.'
end
respond_with(#refund, :location => project_refunds_path(#project))
end
In fact, I would like the :iphone format is handle as :html is ... and not by calling the to_format method as it is specified into the doc.
Solved it by myself.
Just need to add this to an initializer file :
ActionController::Responder.class_eval do
alias :to_iphone :to_html
end
What if you do:
respond_with(#refund, :location => project_refunds_path(#project)) do |format|
format.iphone { whatever you had here before refactoring }
end