Rails 5 action mailer error - ruby-on-rails

I'm having issues with rails action mailer. When I click on my subscribe button I keep getting the same error for almost an hour now, after spending the same amount of time trying to fix it. I don't know what I'm missing or what I need. Any help please. I want the user to click on the subscribe button and to have it save and then send them a verification email.
This is the error message I keep receiving "SubscribersController#show is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot."
This is the code for my controller-
class SubscribersController < ApplicationController
respond_to? :html, :json
def index
#subscriber = Subscriber.new
end
def show
end
def create
#subscriber = Subscriber.new(subscriber_params)
respond_to do |format|
if #subscriber.save
# Tell the UserMailer to send a welcome email after save
SubscriberMailer.welcome_email(#subscriber).deliver_now
format.html { redirect_to(#subscriber, notice: 'User was successfully created.') }
format.json { render json: #subscriber, status: :created, location: #subscriber }
else
format.html { render action: 'new' }
format.json { render json: #subscriber.errors, status: :unprocessable_entity }
end
end
end

Related

Redirect to another page in Ruby on Rails

I want to redirect to another page admin_antenna_reader_rfids_path at the end of the create method. I did:
def create
#antenna_reader_rfid = AntennaReaderRfid.new(antenna_reader_rfid_params)
if #antenna_reader_rfid.save
render json: {status: true}
redirect_to admin_antenna_reader_rfid_path(q#antenna_reader_rfid)
else
render json: {errors: #antenna_reader_rfid.errors.full_messages, status: false}
end
end
I get an error AbstractController :: DoubleRenderError:
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
How can I solve this?
You have to remove the line render json: {status: true} as currently you're trying to make your controller render a json and redirect to an HTML page at the same time. You have to pick one.
To handle multiple request format, you can use respond_to
if #antenna_reader_rfid.save
respond_to do |format|
format.json { render json: { status: true } }
format.html { redirect_to where_you_want_path }
end
else
# same way as above
end
Within the respond_to block, you can render all the request formats as you want, then based on the request header, the controller will choose the corresponding logic to respond to you.
You can't render nor return more than once in a method.

Rails Pundit unable to find policy of nil only on Create action after adding restrictions on some params

I've modified one of my Goal.rb model to only allow one field to be edited by admins. This model and all actions within it was working prior to this update. This update also works for the edit action, but on the create action returns
Pundit::NotDefinedError in GoalsController#create
unable to find policy of nil
I'm hoping this is just a syntax error, I don't understand why it's not working as no model/policy file names have been changed, only the params and policy settings (which work for the edit action)
I thought it might be because I'm calling the policy on #goal while creating it, but how else would I check permissions there, if not this way?
goals_controller.rb:
def create
#goal = Goal.new(permitted_attributes(#goal))
#stuff
authorize #goal
respond_to do |format|
if #goal.save
# format.json { render :show, status: :created, location: #goal }
else
# format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end
end
def update
authorize #goal
update_params = permitted_attributes(#goal)
#
end
respond_to do |format|
if #goal.update(update_params)
# format.json { render :show, status: :ok, location: #goal }
else
# format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end
end
I just realised, you can call permissions on a new class. I had read this three times, but only after posting the question did it click.
I was trying to check the allowed params of #goal, which didn't yet exist and was showing a nil policy, but with Pundit you can run a check against the allowed params of a Class, in this case:
#goal = Goal.new(permitted_attributes(Goal))

No route matches in show action- missing required keys: [:id]

I looked at a few different answers similar to this question, but they all are getting the id passed into the params hash, it is just coming back as a nil value. I cant seem to get the id to be whitelisted and I cant figure out why.
This is my create and show action, also includes the params. I explicitly whitelisted id although I dont know if it is necessary.
def show
#board = Board.find(params[:id])
end
def create
#board = Board.new(board_params)
if #board.save
# flash[:notice] = 'You successfully created your post!'
redirect_to board_path
else
render 'new'
# flash[:danger] = 'One or more errors occurred when processing your post'
end
end
private
def board_params
# params.require(:board).permit!
params.require(:board).permit(:id, :project_name, :project_description, :postition_title, :project_url, :project_headquarters, :application_process)
end
The output of my routes show action
board GET /boards/:id(.:format) boards#show
And the output of the params hash on board#create
Parameters: {"utf8"=>"✓", "authenticity_token"=>"k+KKRhBk4Dnba1vxtFCanI2grfhNXFSgJpfEBLnhPdablfOsXRi1wBehPpM1qgx1pySrqxVHTeiwkneluXwRIQ==", "board"=>{"project_name"=>"sdf", "postition_title"=>"sdf", "project_headquarters"=>"sdf", "project_url"=>"fsd", "project_description"=>"dfs", "application_process"=>"dfs"}, "commit"=>"Create Board"}
Can anyone see what I need to change in order to get the id passed in correctly?
Try this.
Take :id out of params.
def show
end
def create
#board = Board.new(board_params)
respond_to do |format|
if #board.save
format.html { redirect_to #board, notice: 'Board was successfully created.' }
format.json { render :show, status: :created, location: #board }
else
format.html { render :new }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
in create action...
change ..
redirect_to board_path
to...
redirect_to board_path(#board)
###OR
### this calls the show action
redirect_to #board

Rails, respond_to blocks and |format|

Rails scaffold generated the following:
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice => 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
After reading this I understand how the respond_to is working (sort of), but I don't get what format is doing. Shouldn't it be either format.html or format.json and not both? What are these two lines actually doing?
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
Is there an implied if in there? Is it something like
if (format == html) {}
if (format == json) {}
Side note: Why does update require the respond_to block while show will handle /students/1.json or /students/1 without any logic at all?
format is a local variable that respond_to yields. When you do format.html {} you are actually registering a callback block for a format.
Rails goes through the registered formats and tries to find a compatible format to the MIME type in the request. If there is no handler it will raise an error.
This could be explained as something like using syntactic sugar on top of a case statement (the Ruby equivalent of a switch statement). But the analogy is not completely accurate since Rails does a bit of work in matching the request type.
Also the code inside your block is not executed when the format.html block is registered (as it would be if it was just a conditional statement) but rather when respond_to finishes or not at all if you are using for example E-Tag caching.
Why does update require the respond_to block while show will handle
/students/1.json or /students/1 without any logic at all?
Rails handles many actions by using a convention over configuration approach and guessing the intent of the action.
def PostsController < ApplicationController
def index
# rails auto-magically fills in the controller with something
# like this
#posts = Post.all
respond_to do |format|
format.html { render :index }
format.json { render json: #posts }
end
end
def show
# convention over configuration is awesome!
#post = Post.find(params[:id])
respond_to do |format|
format.html { render :show }
format.json { render json: #post }
end
end
def new
#post = Post.new
render :new
end
def edit
#post = Post.find(params[:id])
render :edit
end
end
Rails assumes that there is a resource with the same name as the controller and auto-magically fills in the controller action. It also assumes there is a view in app/views/posts/(:action).html.[erb|haml|slim|jbuilder]. This is known as implicit rendering.
The comments show roughly what action rails attempts.
It does not fill in actions which operate on data (create, update, destroy) since the actual implementation can vary greatly and it's hard to make useful guesses.
Well, it depends on the format of the request. If a request demands HTML from the server, format.html block will be executed, and in the same way, if a request demands JSON format, format.json will be executed.
Rails will automatically(read: magically) handle the if (format == html) part for you. All you have to do is fill in the blanks. Same way, you can write a block for XML starting with format.xml.
And for the side note, I think you have said it otherwise. update method doesn't require respond_to block, while show requires. And the reason is very simple: update method is there to update the Model, and then, redirect you to somewhere, while show will always return you something. In your case, /students/1 will return you the first student created in the database, and the response will be HTML, while /students/1.json will return you the same result, but response will be JSON this time.
Well you could very well replace 'format' with 'foo' or 'banana' or whatever you want. It is just the variable name in this case because the variable that is sent to your block by respond_to is passing along the format as requested by the incoming http request's Accept header.
Sometimes you'll see 422 "Unacceptable" errors in your logs because you are receiving a request with an Accept header that does not request a mime type your app knows about.
As it is, your callers should be using a browser or be a JSON consumer sending the proper headers to receive responses from the boilerplate.

At the controller level, how to prevent an anonymous user from posting?

The following is a standard posts#create action (app/controllers/posts_controller.rb).
At the controller level, I want to prevent an anonymous user (a user who is not signed in) from being able to save a post. As a secondary objective, I don't even want to execute the Post.new line if the user is not signed in. I want to know what is the best practice for accomplishing this.
Also, as a side note, I am unsure of how to write the json portion of the response. If I am redirecting with an alert message in the HTML context, what would be a good thing to respond with in JSON world?
def create
#posting = Post.new(posting_params)
respond_to do |format|
if #posting.save
format.html { redirect_to #posting, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #posting }
else
format.html { render action: 'new' }
format.json { render json: #posting.errors, status: :unprocessable_entity }
end
end
end
For the time being I have the following line in my code, above the Post.new line:
redirect_to home_path, warning: 'You must be logged in to post.' and return unless user_signed_in?
I suppose another option is something like the following, placed above the if #posting.save line. But really, I am looking to see what other folks would do.
unless user_signed_in?
format.html { redirect_to home_path, alert: 'You must be logged in to post.' and return }
format.json { render json: .....not sure what to put here..... }
end
Your advice is greatly appreciated.
A before_filter is good for this sort of thing:
before_filter :confirm_user_signed_in, only: [:new, :create]
def confirm_user_signed_in
unless user_signed_in?
respond_to do |format|
format.html { redirect_to home_path, alert: 'You must be logged in to post.' and return }
format.json { render json: .....not sure what to put here..... }
end
end
end
As far as what to render in the JSON scenario, you can render nothing at all, but with a 403 (Forbidden) status. You can optionally include some data explaining why the 403 occurred, but there's no standard for how that data will be displayed. Some frameworks (Backbone, I think) will look for a hash containing an errors key, which can be set to the reason.
Something like:
format.json { render json: { errors: ["Login required."] }, status: 403 }
The better practice is to use before filter and mention list of actions like this:
before_filter :require_login, :only => [:new, :create]
Try using the cancan gem. You can not only prevent the unwanted user from posting, also you can do various other permissions, which do not bloat the controller. These permissions are defined by you in a separate file called ability.rb.
cancan Railscast
cancan Github

Resources