Rails: code in model or controller - ruby-on-rails-3

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.

Related

Rails: Nested resource and specifying the "nester"

A company has many properties. A property has one company.
In my routes file I got:
resources :companies do
resources :property_managers
end
In the property_manager_controller, my create action looks like this (default scaffold implementation slightly modified to accommodate the company):
def create
#property_manager = PropertyManager.new(params[:property_manager])
#property_manager.company_id = params[:company_id]
respond_to do |format|
if #property_manager.save
format.html { redirect_to company_property_managers_path, notice: 'Property manager was successfully created.' }
format.json { render json: #property_manager, status: :created, location: #property_manager }
else
format.html { render action: "new" }
format.json { render json: #property_manager.errors, status: :unprocessable_entity }
end
end
end
Is there a way in which I do not have to explicitly set the company_id, since it is known within the context of the URL/route?
I guess you could do something like the following, not sure if it's better or not:
class PropertyManagersController < ApplicationController
before_filter :find_company
def new
#property_manager = #company.property_managers.build
end
def create
#property_manager = #company.property_managers.build(params[:property_manager])
respond_to do |format|
...
end
end
private
def find_company
#company ||= Company.find(params[:company_id])
end
end

No route matches {:action=>"show", :controller=>"restaurants"}

If I want to go with my home page clicking on the map localhost:3000/maps gets out this error No route matches {:action=>"show", :controller=>"restaurants"}
controllers/maps_controller.rb
def index
#maps = Map.all
#json = Map.all.to_gmaps4rails do |map, marker|
marker.infowindow info_for_restaurant(map.restaurant)
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #maps }
end
end
def show
#map = Map.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #map }
end
end
private
def info_for_restaurant(restaurant)
link_to restaurant_path do
content_tag("h2") do
restaurant.name
end
end
end
routes.rb
resources :restaurants
resources :maps
This is answer for my question:
controllers/maps_controller.rb
def index
#maps = Map.all
#json = Map.all.to_gmaps4rails do |map, marker|
marker.infowindow render_to_string(:partial => "/maps/maps_link",
:layout => false, :locals => { :map => map})
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #maps }
end
end
views/maps/_maps_link.html.erb
<div class="map-link">
<h2><%= link_to map.restaurant.title, map.restaurant %></h2>
</div>
You referred to restaurant_path within info_for_restaurant, which is part of MapsController. Rails met error here.
You need to either define the restaurant_path in restaurant controller, or comment out this function in maps controller at this moment.
Your approach is wrong in several levels. Let's work on them, one at a time:
1) Your call to the route helper is wrong:
restaurant_path is the route helper for a show action. A show action needs an id parameter to be valid. Your call is missing a parameter.
So, your code must be something like this:
def info_for_restaurant(restaurant)
link_to restaurant_path(restaurant) do
content_tag("h2") do
restaurant.name
end
end
end
To see the parameters needed for each action, you can run rake routes on the console.
However, this does not solve the problem, as you're also:
2) Calling view helpers from your controller
link_to and content_tag are view helper methods, and you don't want to bother your controller with view issues. So, the best way to solve this problem is to move your info_for_restaurant method to a helper, and call it from a view instead.
So, now, your controller will not assign anything to #json, and the last line of your view will look like this:
<%= gmaps4rails #maps.to_gmaps4rails {|map, marker| marker.infowindow info_for_restaurant(map.restaurant) } %>

Avoid index url after failing create

When you create a User in rails through the create action, the url is changed to
http://myapplication.com/users with POST
before being redirected elsewhere. If validation fails, it appears that the above URL is retained. If you then refresh, you end up on the index page (as it's now a GET).
I would expect if validation was failed the url would remain as
http://myapplication.com/users/new
As i don't have an index page, this is causing me problems. Is there a way to resolve this please?
This depends on the logic in the respond_to block in your controller.
This is a typical example of the create action in users_controller.rb:
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
So if the save fails, the new action is rendered again.
In your UsersController, do like this:
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url # save success will return to root page
else
render 'new'
end
end

Rendering a like/unlike button in rails with jQuery

I'm using jquery to render a like button on a story. I have two models story and like
Here's the likes controller code:
def create
#like = Like.new(params[:like])
#story = Story.find(params[:story])
#like.story = #story
if #like.save
respond_to do |format|
format.html
format.js
end
end
end
def destroy
#like = Like.find(params[:id])
##story = #like.story
#like.destroy
respond_to do |format|
format.html { redirect_to stories_url }
format.js
format.json { head :ok }
end
end
This is the button partial (stories/like_button):
<% unless user_likes_story?(#story, current_user) %>
<%= button_to 'like', "/likes?story=#{#story.id}", :id => 'like_button', :remote => true %>
<% else %>
<%= button_to 'liked', #liked, :class => 'like_button unlike', :id => 'unlike_button', :remote => true, method: :delete %>
<% end %>
The problem is that my create.js.erb, when rendering the 'unlike' button, doesn't properly load the #liked instance variable, because it's being set in the #show action of the stories controller before the user has liked the story, so I can't figure out how or where to set it so the JS will render the unlike properly. I'm probably making this harder than it has to be, but...
create.js.erb
$('.button_to').replaceWith('<%=j render 'stories/like_button' %>');
$('#story_likes_count').replaceWith('<%=j render 'stories/likes_count' %>');
Here's how I tried setting #liked, in stories#show
def show
#like = Like.new
#story = Story.find(params[:id])
if current_user
#liked = Like.find_by_user_id_and_story_id(current_user,#story)
end
respond_to do |format|
format.html # show.html.erb
format.json { render json: #story }
end
end
Any idea how to do this properly? Should I just move the partial out of the stories folder?
The solution was pretty simple. In the controller, doing this:
format.js {#liked = #like}
Passes the variable and makes it available to the partial when it's rendered.

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