On a project show page, I pass a very simple parameter on my 'create new task' that stores which project its from:
@project.id), :class => "btn btn-info col-md-12" %>so that when i create a new task for it, it stores it in the URL on my new task form like this:
http://localhost:3000/task/new?project_id=5
My New form is as follows:
<div class="container sign-in-register">
<div class="authform">
<%= form_for @task, :html => {:multipart => true} do |f| %>
<h3>Add a task for this project...</h3><br/>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= hidden_field_tag 'project_id', @project_id %>
<%= f.fields_for :taskrelationships do |ff| %>
<%= ff.hidden_field :taskproject_id, value: @project_id %>
<%= ff.label :task_url %>
<%= ff.text_field :task_url, class: 'form-control' %>
<% end %>
<br clear="all">
<%= f.submit "Save Task", class: "btn btn btn-info" %>
<% end %>
</div>
</div>
As you can see i'm using nested attributes in the form (I am creating both a task and a TaskRelationship. Now, when I try to save without filling out all the required fields a validation is thrown but for some reason it redirects me to:
http://localhost:3000/tasks
instead of the original:
http://localhost:3000/tasks/new?project_id=5
I have read many posts and none seem to answer this particular case. The stackO post below was close but when I try it with task instead of user it still cannot find the task_ID
Render error on new page with customize url like http://localhost:3000/education_informations/new?user_id=10
How can I have rails simply render the same exact url as I started with - it seems like this should be easy so must be missing something small.
My controller actions:
def new
@project_id = params[:project_id]
@task = Task.new
@task.taskrelationships.build
end
def create
@project = Project.find(params[:project_id])
@task = Task.new(task_params)
if @task.save
flash[:success] = "This task has been added."
@task.taskrelationships.create!(@taskrelationships_params)
redirect_to tasks_project_path(@project)
else
@task.taskrelationships.build(@taskrelationships_params)
flash[:alert] = @task.errors.full_messages.to_sentence
render :new
end
end
private
def task_params
@taskrelationships_params = params.require(:task).permit(taskrelationships_attributes: [
:task_url,
:taskproject_id
])[:taskrelationships_attributes]["0"]
params[:task].delete(:taskrelationships_attributes)
params.require(:task).permit(
:name,
:user_id,
taskrelationships_attributes: [
:task_url,
:taskproject_id
]
).merge(owner: current_user)
end
UPDATE W / ROUTES
resources :projects do
resources :reviews, except: [:destroy]
member do
get :tasks
end
end
resources :tasks
resources :taskrelationships, only: [:create, :destroy] do
post :vote, on: :member, controller: "task_relationships"
end
thanks for any assistance...
Ok firstly an explanation as to what is going on here:
When you invoke http://localhost:3000/task/new?project_id=5
you are actually being routed to the new action on the task controller (with a project_id param).
Your new action then sets the variables and rails will render the new.html.erb which contains your new task form.
When you submit the form it actually is doing a http POST to /tasks, which routes to the create action of your tasks controller. That url and http method is a result of what is generated from the form_for helper:
<%= form_for @task, :html => {:multipart => true} do |f| %>
This is why the url changes from /tasks/new?project_id=5
to /tasks
Now the create action if it fails the validation simply renders the new form - it is not redirecting anywhere - the url remains unchanged from what it was when it entered this action - meaning, it remains as /tasks
.
You do not actually need to navigate to /tasks/new?project_id=5 to render the new form but what you do need to do is set @project_id in the controller so the view has access to that variable (just as it does in the new action):
def create
@project = Project.find(params[:project_id])
@task = Task.new(task_params)
if @task.save
flash[:success] = "This task has been added."
@task.taskrelationships.create!(@taskrelationships_params)
redirect_to tasks_project_path(@project)
else
@task.taskrelationships.build(@taskrelationships_params)
@project_id = @project.id
flash[:alert] = @task.errors.full_messages.to_sentence
render :new
end
end
So, to clarify the change in url is not a redirection it's just that the form is posting to a different url than /tasks/new, and this is actually just a cosmetic issue.
Now if it is a concern to you, you can change the routing to something like the following:
resources :tasks, except: [:create, :new]
post 'new_task' => 'tasks#create'
get 'new_task' => 'tasks#new'
This is mapping the POST and GET http methods to /new_task so the url appears the same for the new and create action invocations. Note you do need to change the url in the form_for helper to use this new route:
<%= form_for @task, url: 'new_task', multipart: true do |f| %>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With