I want to add service objects in to my controller. Is there any chance to include flash messages in to this service object?
user_stocks_controller
class UserStocksController < ApplicationController
def create
#user_stock = UserStocksCreator.new(current_user, params).call
redirect_to my_portfolio_path
end
end
service objects user_stocks_creator
class UserStocksCreator
def initialize(current_user, params)
#current_user = current_user
#params = params[:stock_ticker]
end
def call
stock = Stock.find_by_ticker(params)
if stock.blank?
stock = Stock.new_from_lookup(params)
stock.save
end
#user_stock = UserStock.create(user: current_user, stock: stock)
flash[:success] = "Stock #{#user_stock.stock.name} was successfully added to portfolio"
end
private
attr_accessor :current_user, :params
end
With this code I have an error:
undefined local variable or method `flash'
The flash method is only available in the controller. When you want to set the flash in the service object then you need to pass the flash to the service object.
# in the controller
def create
#user_stock = UserStocksCreator.new(current_user, params, flash).call
redirect_to my_portfolio_path
end
# in the service
class UserStocksCreator
def initialize(current_user, params, flash)
#current_user = current_user
#params = params[:stock_ticker]
#flash = flash
end
def call
# unchanged...
end
private
attr_accessor :current_user, :params, :flash
end
Related
I am creating a job for the first time in Rails to send an email to the current_user when they create a form.
Create method
def create
#pdform = Pdform.new(pdform_params)
if user_signed_in?
#pdform.user_id = current_user.id
end
respond_to do |format|
if #pdform.save
SubmissionJob.perform_later(current_user, #pdform)
format.html { redirect_to new_pdform_requisition_path(#pdform) }
else
format.html { render :new }
end
end
end
I am passing the current_user and the #pdform in the job arguments.
Submission job
class SubmissionJob < ApplicationJob
queue_as :default
def perform(*args)
#user = current_user
NewPdform.notify_user(#user, #pdform).deliver
end
end
If I am passing the current_user object in the parameters in the arguments andassigning it to the #user variable how is there no defined method for current_user?
I have this check to set the user_id of the pdform to the current_user id and that is being populated when I create the form which means there is a user. So why would this result in a NameError?
The current_user object is only available by default in controllers and views.
You need to pass it to your job as an argument:
Replace:
def perform(*args)
By:
def perform(current_user, pdform)
or even :
def perform(user, pdform)
NewPdform.notify_user(user, pdform).deliver
end
Experimenting with ruby on rails.. I put a new Post form on a users show page.(i.e. 0.0.0.0:3000/users/2) I'm trying to extract the user's id and insert it into a 'user_id' field in the Post table when you create a new post. So when the form is submitted from the user's page, I can link it to the user that wrote it.
models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
before_save :create_user_id
def create_user_id
self.user_id = current_user
end
end
models/user.rb
class User < ActiveRecord::Base
has_many :posts
end
helpers/application_helper.rb
module ApplicationHelper
def current_user
#current_user ||= User.find(params[:id])
end
end
controllers/post_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
#page_title = #post.title.capitalize
#author = User.find(#post.user_id)
#author_url = "/users/" + #post.user_id.to_s
end
def create
#post = Post.create(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
# private
private
def post_params
params.require(:post).permit(:title, :body, :user_id)
end
end
The error I get:
Couldn't find User without an ID
Extracted source (around line #15):
#post = Post.find(params[:id])
#page_title = #post.title.capitalize
>>#author = User.find(#post.user_id)
#author_url = "/users/" + #post.user_id.to_s
end
If I test and change my application_helper.rb to this it works, and inserts 2 into the Post's user_id field. The current set up just returns nil
module ApplicationHelper
def current_user
#current_user = 2
end
end
First you want to get the current user, for now you can test using something like this:
#current_user ||= User.find(2)
Note that there will not be an :id param available on a create call, :id refers to a specific member of your resource so in this case if get http://localhost:3000/posts/1 posts would be the resource and 1 would be the param :id so this would not return the current_user you expected.
Then association should do all of the work for you and there is no need for the create_user_id method. All you would have to do is tweak your create method to
#post = current_user.posts.create(post_params)
I am building an application that allows users to create a trip. However, for some reason I am not sure if I am truly utilizing the power of rails or am I being redundant in my code. In the following example you will see a trip controller where a trip can be created and then displayed. Everything works, I just want to make sure I am going about it in the most minimal fashion.
class TripsController < ApplicationController
def new
#user = User.find(session[:id])
#trip = Trip.new
end
def create
#trip = Trip.create(trip_params)
#user = User.find(session[:id])
redirect_to user_trip_path(#user.id, #trip.id)
end
def show
#trip = Trip.find(params[:id])
end
private
def trip_params
params.require(:trip).permit(:where, :when, :price_per_person)
end
end
To tighten it up, "scope the trip to the user".
class TripsController < ApplicationController
before_filter :find_user
def new
#trip = #user.trips.build #assuming a User has many trips
end
def create
#trip = #user.trips.create(trip_params) #you may want to add an if else here to catch bad trips
redirect_to user_trip_path(#user.id, #trip.id)
end
def show
#trip = #user.trips.find(params[:id])
end
private
def trip_params
params.require(:trip).permit(:where, :when, :price_per_person)
end
def find_user
#user = User.find(session[:id]) # or current_user if you are using popular authentication gems
end
end
It's about readability too, not just less lines.
I'm trying to set a variable in my before_filter, but always get the error "undefined local variable or method 'question' for AnswersController":
class AnswersController < ApplicationController
before_filter :get_question
def create
#answer = question.answers.new(params[:answer])
#answer.user = current_user
#answer.save
flash[:notice] = 'Answer posted successfully.'
redirect_to request.referer
end
def get_question
question = Question.find(params[:question_id])
end
end
Thank you very much!
You need to make it an instance variable using the # symbol. Also, you may want to consider moving this into a private method (see below) since this most likely is not a public action.
class AnswersController < ApplicationController
before_filter :get_question
def create
#answer = #question.answers.new(params[:answer])
#answer.user = current_user
#answer.save
flash[:notice] = 'Answer posted successfully.'
redirect_to request.referer
end
private
def get_question
#question = Question.find(params[:question_id])
end
end
In my controller i have an action which does not have a corresponding view. Precisely: the upload action for uploading images. However, i require the current users id to store the image url. But the current_user method always returns nil, as the action by itself does not have a view. In such scenarios how do i fetch the current_user? I am using authlogic. My application_controller.rb contains the following:
class ApplicationController < ActionController::Base
helper :all
helper_method :current_user_session, :current_user
filter_parameter_logging :password, :password_confirmation
protect_from_forgery
def correct_safari_and_ie_accept_headers
ajax_request_types = [ 'application/json', 'text/javascript', 'text/xml']
request.accepts.sort!{ |x, y| ajax_request_types.include?(y.to_s) ? 1 : -1 } if request.xhr?
end
private
def set_cache_buster
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
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.record
end
end
EDIT: All other actions in the controller are able to access the current_user helper method. Only the upload action is not able to. Code:
Controller:
class ImageStacksController < ApplicationController
def upload
# Using swfupload.
image_stack_params = {
:caption => params[:caption],
:swf_uploaded_data => params[:link]
}
# current_user returns nil, even with user logged in!!
# Occurs only in the upload action and no other action in this controller.
logger.info("Current User: #{current_user}") #Returns nil
#image_stack = current_user.image_stacks.create! image_stack_params
respond_to do |format|
format.js { render :json => #image_stack }
end
end
def edit
logger.info("Current User: #{current_user}") #Returns current user
end
def new
logger.info("Current User: #{current_user}") #Returns current user
end
def update
logger.info("Current User: #{current_user}") #Returns current user
end
def destroy
logger.info("Current User: #{current_user}") #Returns current user
end
end
Model:
class ImageStack < ActiveRecord::Base
belongs_to :user, :class_name => "User", :foreign_key => "user_id"
upload_image_to_s3 :link
def swf_uploaded_data=(data)
data.content_type = MIME::Types.type_for(data.original_filename)
self.link = data
end
end
The controller method is really just that, a class method. It does not require a view. My making it a private method the method is not available outside the class or other classes inheriting from it and as such it is correctly not available to the view. Your problem suggests that your user is not logged in or something else is wrong. Do you have a require_user method?
#application_controller
private
def require_user
unless current_user
store_location
flash[:notice] = t(:must_be_logged_in)
redirect_to user_login_path
return false
end
end
def store_location
session[:return_to] = request.request_uri
end
#user.rb
has_many :images
#image.rb
belongs_to :user
# image_controller.rb
before_filter :require_user
def create
#photo = #item.images.new(:photo => params[:photo], :user => current_user)
Edit:
Your current_user method is a ApplicationController method which is already inherited:
ImageStacksController < ApplicationController
This:
helper_method :current_user_session, :current_user
is providing the methods to the view.
The difference between the upload action and all the others is update is being called by javascript. I remember doing a similar uploader and having to pass the authenticity token. Is anything else being reported in the log?
This might be of use to you: http://github.com/JimNeath/swfupload---paperclip-example-app
Making the authenticity token available to js goes something like this:
- content_for :head do
= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery?
Now you add the field to swflupload the same way you added current_user.