I'm trying to curl POST my Rails application in order to create a new Entry object. The problem is my entries_controller Create action looks like this:
def create
#user = current_user
#entry = #user.entries.build(params[:entry])
respond_to do |format|
if #entry.save
format.html { redirect_to landing_page_url, notice: 'Entry was successfully created.' }
format.json { render json: #entry, status: :created, location: #entry }
else
format.html { render action: "new" }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
Calling #user.entries.build just returns an exception because current_user doesn't exist. The thing is the Create action works well when I use the browser to create an Entry (as I login and create the current_user variable) but I do not know if it's possible to curl POST and create an Entry without changing the controller logic. And if it's not possible, could someone help reach the right direction towards building the controller logic (compatible with curl POST)?
I'm sorry if this is a dumb question, I'm fairly new to all this.
PS: I'm using Rails 3.2.3, if that's of any help.
Not sure how you create current_user (what it's based off), but this must exist for your method to work.
If you can pass a param to your action that specifies the user and set current_user as current_user ||= params[:user]... beware of the security implications of this.
You really should have a before_filter on your action to set current_user (via login, I'm presuming).
Related
Quick question, I've been trying for the last couple hours to discern what is causing the following behavior but it's just beyond my grasp.
I have this two actions on my 'UsersController':
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
flash[:success] = 'Wellcome, %s! You have successfully
registered.' % [#user.name]
format.html { redirect_to login_path }
format.json { render :show, status: :created, location: #user }
else
flash.now[:error] = 'Hmm... There seems to be some errors.'
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
Basically, we render a clean 'new' view, try to register a new user, and if the creation of a user fails, the application should flash a message for the current action (the create action), and render the 'new' view, updating the previous one with the flash information and the errors of the #user variable.
The problem is that, although the server processes the response just fine, the browser does not update the page, never re-renders the page, it keeps the stale 'new' view. I've looked the response with chrome's web tools and it bears the updated view, but for some reason the browser just won't render it.
I think it has something to do with caching, but really I'm out of my element here. If instead of rendering I just redirect to the new action, the flash works fine (removing the .now(), that is), but this way I lose the #user, which I would like to keep with it's full functionality.
Any ideas why this behaves like this, or at least how to solve it?
If you redirect_to the new action, when the user submits, it will still post to the create action and the user_params would still take effect. Simplying rendering :new on the already new page will not perform a fresh request/response. To initiate a fresh request you will have to use redirect_to.
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
I have a rails app that has multiple ways of creating tasks
a) A normal task new screen with lots of options
b) A quick task create screen which has the minimum actions and only has the minimum fields to enable quick creation. And a list of the actions
After the create succeeds I want
a) to redirect to the standard show form
b) to redirect back to the quick edit page with a blank quick creation box and the new task in the list.
If create fails on validation I want
a) to redirect to the edit screen with the fields highlighted
b) to redirect to the quick create screen with the fields highlighted and the data still there.
I've tried editing the create respond_to if.save? but that seems to apply to everything in both cases.
There's a slight complication in that I create tasks either generically (no client selected) or as a nested route under client where the client is autoselected, and ideally I'd like to go back to that nested route location.
I'd like to control that respond to by using an if parameter that recognises where the call is coming from
if from quick_create
if #task.save?
redirect
else
reload table and clear
if from new
if task.save?
Any ideas?
Adding current controller code and routes:
routes.rb
get 'tasks/quick_create' => 'tasks#quick_create'
-----
resources :clients do
match 'tasks/quick_create' => 'tasks#quick_create'
----
tasks_controller.rb
def create
#task = Task.new(params[:task])
#task.practice_id = current_user.practice_id
unless #task.recurring.present?
#task.build_recurring
end
#task.create_recurring_tasks
if params[:batch_task] == "Create Task"
#client = Client.find(params[:client_id])
#task.build_batch_task(#client)
end
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
def quick_create
if params[:client_id]
#client = Client.find(params[:client_id]).tasks
#tasks = #client.accessible_by(current_ability, :read).order(:due_date)
else
#tasks = Task.accessible_by(current_ability, :read).order(:due_date)
end
#task = Task.new
#task.status = "Not Complete"
##task.task_files.build
#task.build_recurring
respond_to do |format|
format.html # index.html.erb
format.json { render json: #tasks }
end
end
Ibasically want to control the respond do bit with something like
if request.path.include? "quick_create"
And be able to flag up the errors on quick create. There appears to be two things.
1. The request.path if statement doesn't work
2. The #task when attempting to feed back to the quick_create page hits an error (since it expects both #task and #tasks, I think).
Anyway....
I imagine You may have two options -
specify some custom parameter inside URL and use it to decide where redirect to
or use different actions as already suggested.
If You are having problems with two different create actions, post current controller code and Your routes otherwise we can't help You.
I am using almost the code from the regular scaffold. The only change is the 4.times block where I make 4 answer objects on the question. The reason is that I have the corresponding input fields in the view. Now, if the validation fails it renders the new.html.erb again, however after what I have been reading it does not invoke the "new" action again. However I am depending on the 4.times block because otherwise the loop in the view have no answers to loop through. How do I fix this? I tried redirecting but then the error messages disappered.
New action
def new
#question = Question.new
4.times do
#question.answers.build
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #question }
end
end
Create action
def create
#question = Question.new(params[:question])
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render json: #question, status: :created, location: #question }
else
format.html { render action: "new" }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
Exactly as your title suggests: render does just render (the template belonging to) the action and not perform the action itself.
To get your prebuilt answers rendered again in a failed create call, I suggest removing the :reject_if condition from the nested attributes setup. This way, empty submitted answers are preserved. To prevent them from being written to the database, just add regular validations to the Question model...
What you need to look at is the #question in your create action. In theory it should contain the 4 newly built answers so redisplaying the form would also contain these.
If they are not written you may have to look at the accepts_nested_attributes_for to make sure it gets deserialized correctly from the request.
I have a fairly standard controller with a create method and some validations.
def create
#type = Type.new(params[:type])
respond_to do |format|
if #type.save
format.html { redirect_to types_path, notice: 'Type was successfully created.' }
format.json { render json: #type, status: :created, location: #type }
else
format.html { render action: "new" }
format.json { render json: #type.errors, status: :unprocessable_entity }
end
end
end
The problem is that when a validation fails, I get the errorMissing template ontology/types/create, as if the render action: "new" weren't there. If I replace it with a redirect_to then it works as expected, but then it seems I can't pass the form errors along.
I know that there is a #type instance (with #type.errors) from the original call of new, and throwing it just before the render call confirms this.
The same thing is happening when a validation fails on update It seems like the render call is just being ignored!
NOTE: my routing structure is a little unconventional, but I see not reason why this should be related.
This looks very similar: Path defined in controller and action is getting ignored, Ruby on Rails
Based on the answer to that question, I'm guessing that something is missing that is needed for rendering the new view, and as a result rails is just skipping the render call altogether and rendering create.
Can you show the new controller action and view?