Render in JSON in Rails - ruby-on-rails

I've got a controller with a single index action:
chat_room_controller.rb
class ChatRoomController < ApplicationController
before_action :authenticate_user
def index
#current_user = User.find(session[:user_id])
end
end
I need to render my variable #current_user in JSON format. So I need to create a show action or I can simply handle this situation adding:
respond_to do |format|
format.json
end
I need the format JSON of this variable for reference in an AngularJS module so I also need access to it.

If you want to have the current_user method to be available in your rails views, you should create a helper method in your ApplicationController, and then in all controllers, which inherit from it, the view will have the current_user helper:
class ApplicationController
protected
def current_user
#current_user ||= User.find(session[:user_id])
end
helper_method :current_user
end
class ChatRoomController < ApplicationController
def index
render json: current_user
end
end

Related

How to make #current_user available in my views?

In my application controller I have a module that I include like:
require 'current_user'
class ApplicationController < ActionController::Base
include CurrentUser
end
So if there is a token cookie set, it looks up the user.
In my views i am doing this:
<% if #current_user.present? %>
...
..
This doesn't work currently in my views because there is no #current_user or current_user in my views.
How can I create a #current_user variable globally for all my view pages to access?
I'm not sure what your module does, but you can just make a method on in ApplicationController:
def current_user
# ... fetch current_user somehow...via your module method, or session:
#current_user ||= session[:user_id] ? User.find(session[:user_id]) : nil
end
Then you can access it in your views via:
<% if current_user.present? %>
If you really want to force it to be #current_user, I guess the easiest way would be to add it as a before_action:
class ApplicationController < ActionController::Base
before_action :set_current_user
private
def set_current_user
#current_user = session[:user_id] ? User.find(session[:user_id]) : nil
end
end
Now you can access it in views via #current_user, but it will be eagerly fetched even if you aren't using it in your views. Using first method will only query for current user if you use it.
In my module I just some ruby metaprogramming to include it in my application_controller class:
module CurrentUser
def self.included(base)
base.send :helper_method, :current_user
end
end
Now current_user works in my views.

Rails API - keeping an application controller method DRY

I have a method in my Rails application controller that I call when I am creating a new Post. I have also created an API to create a new Post. However, it seems that I need to repeat the code for my application controller method in my API BaseController. Where is the best place to put the application controller method in my Rails app so that I do not have to repeat the code for the API? Is there a way that the API base controller can inherit from the ApplicationController?
Rails app
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
#post.text = foo_action(#post.text)
if #post.save
redirect_to posts_path
else
render :new
end
end
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def foo_action(string)
return string
end
end
Rails API
class Api::V1::PostsController < Api::V1::BaseController
def create
#post = Post.new(post_params)
#post.text = foo_action(#post.text)
if #post.save
respond_with(#post)
end
end
end
class Api::V1::BaseController < ActionController::Base
respond_to :json
def foo_action(string)
return string
end
end
Based on #phoet's recommendation in the comments above, I moved the foo_action method to the Post model:
class Post < ActiveRecord::Base
def foo_action
string = self.text
return string
end
end
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
#post.text = #post.foo_action
if #post.save
redirect_to posts_path
else
render :new
end
end
end
class Api::V1::PostsController < Api::V1::BaseController
def create
#post = Post.new(post_params)
#post.text = #post.foo_action
if #post.save
respond_with(#post)
end
end
end

Code in each controller method

I have a controller and every method of it starts with the following code:
#user = UserData.find_by_login(session[:cuser])
if #user == nil
redirect_to(:controller=> 'user_data', :action=> 'login')
return
end
I'm just wondering if it is possible to avoid code duplication in this case ?
Yes, use a before_filter
class YourController < ApplicationController
before_filter :check_user
def check_user
..
end
end
Absolutely.
class MyController < ApplicationController
before_filter :ensure_logged_in
# actions here.
def ensure_logged_in
#user = UserData.find_by_login(session[:cuser])
if #user == nil
redirect_to(:controller=> 'user_data', :action=> 'login')
end
end
end
You shouldn't need to worry about the 'return', as rails will bail out of the filter pipeline once the redirect happens.
To avoid duplication you just need to add before_filter in every controller where you want to check user authentication.
class SomeController < ApplicationController
before_filter :authenticate_user
end
then add your user authentication logic in application controller something like this,
class ApplicationController < ActionController::Base
private
def current_user
#current_user ||= UserData.find_by_login(session[:cuser]) if session[:cuser]
end
helper_method :current_user
def authenticate_user
redirect_to({:controller=> 'user_data', :action=> 'login'}, :alert => "Not authorized") if current_user.nil?
end
end
You can use current_user helper method in every controller to get current user.
Try to use before filter. This should be fine

Get value from session on every method of every controller

I have some controller and in each method of each controller I have next code:
#user = session[:user]
Is there a way to avoid putting this code on every method of each controller?
You can add your code in ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :current_user
def current_user
#user = session[:user]
end
end
The anwer of #nash is fine, and here is an alternative providing helper methods you can use in every method/view. This is the way gems like Devise go:
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
helper_method :user_signed_in?
private
def current_user
#current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
end
def user_signed_in?
return 1 if current_user
end
def authenticate_user!
if !current_user
flash[:error] = 'You need to sign in before accessing this page!'
redirect_to signin_services_path
end
end
end

Authlogic, Namespace and private methods in ApplicationController

I am troubleshooting why my ApplicationController's methods don't seem to work in my namespaced admin area and it seems like when I'm in a namespace I cannot access my ApplicationController's private methods, is this right?
If it is like that, what's the best practise to reuse something like Authlogic's example ApplicationController methods in my namespaced controller? I could easily copy and paste the methods to an AdminController or something, and I could also un-private these methods - but this doesn't seem like such a good way to do it.
Here's what the example ApplicationController from Authlogic (and mine) looks like:
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user_session, :current_user
private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.user
end
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
# and some more methods here...
end
And that's how I inherit from it in my namespace:
class Admin::DashboardController < ApplicationController
layout 'administration'
require_user # fails
def index
end
end
Thanks for your help,
Arne
You should use before_filter in Admin::DashboardController:
class Admin::DashboardController < ApplicationController
layout 'administration'
before_filter :require_user
def index
end
end
I haven't used authlogic, but maybe you need to change
require_user
to
before_filter :require_user

Resources