I have a Job model that contains a Company_id as a foreign key. On the Job new page, I want to create a new job using simple form like this
<%= simple_form_for (#job) do |f| %>
<%= f.input :title, label: "Title of job" %>
<%= f.submit 'Create', class: "btn btn-success" %>
<% end %>
This is my nested route
resources :companies do
resources :jobs, only: [:show, :new, :create, :update, :destroy]
end
In my jobs controller new and create method, I have
def new
#job = Job.new
end
def create
#job = Job.new(job_params)
#company = params[:company_id]
#job.company_id = #company
if #job.save
redirect_to company_job_path
else
render :new
end
end
This is the route to the job show page
company_job GET /companies/:company_id/jobs/:id(.:format) jobs#show
and the job create page
company_jobs POST /companies/:company_id/jobs(.:format) jobs#create
I keep getting the error below when I try to create a job using simple form.
No route matches [POST] "/jobs"
Any help would be appreciated.
Just add <%= simple_form_for [#company, #job] do |f| %> instead of <%= simple_form_for (#job) do |f| %> I suppose you have #company set when form is rendered.
According your nested routes you need to set company before jobs
so either use before action set company of find company before use this
in controller
before_action :set_company
def new
##company = Company.find(params[:company_id])
#job = #company.jobs.new
end
private
def set_company
#company = Company.find(params[:company_id])
end
in view pass full url
<%= simple_form_for #job, :url => company_jobs_path(#company, #job), :method => :post%>
<%= f.input :title, label: "Title of job" %>
<%= f.submit 'Create', class: "btn btn-success" %>
<% end %>
Related
I'm working on subscribing application but I've been stacking with creating subscription on the show/page of product. Because of the error
ActionController::ParameterMissing (param is missing or the value is empty: subscription):
routes.rb
resources :products do
resources :subscriptions, only: [:create]
end
products/show.html.erb
<div class="subscribe">
<%= form_with(model: #subscription, url: product_subscriptions_path(product_id: #product.id)) do |f| %>
<div>
<%= f.text_field :email %>
<%= f.submit "Register", class: "btn"%>
</div>
<% end %>
</div>
products_controller.rb
def show
#product = Product.find_by_id(params[:id])
#subscription = Subscription.new
end
subscription_controller.rb
def create
#product = Product.find(params[:product_id])
#subscription = #product.subscriptions.build(create_params)
#subscription.save
end
def create_params
params.require(:subscription).permit(:email, :product_id)
end
The url helper needs two parameters here, as it is a nested route.
url: product_subscriptions_path(product: #product, subscription: #subscription))
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| %>
Since Rails default behaviour in forms is with remote: true, you can move the content of the form to a partial(let's name it _my_form.html.erb), add to the controller action (let's say in create action):
respond_to do |format|
format.js {}
end
Then add a create.js.erb file where you will render the form partial
$("#form").html(
"<%= j render partial: 'my_form', locals: { entity: #entity } %>"
);
Thus, validation errors and all attributes will be accessible inside the form and there is no need to hack the "Rails approach"
I had to adapt and experiment with the currently accepted answer,
and the following ended up working well (using schools rather than tasks):
In config/routes.rb:
resources :schools do
...
end
post 'schools/new' => 'schools#create'
And create the form like:
= simple_form_for [#school], url: 'new' do |f|
Thus the path /schools/new was preserved on validation :)
Cities#new controller shows error involving cities_path, but I don't have it in any file nor in CitiesController. I checked all files, tried to restart the server but still nothing.
undefined method `cities_path' for #<#<Class:0x007f9e4c1cb348>:0x00000003836140>
Did you mean? city_path
CitiesController
class CitiesController < ApplicationController
def index
#cities = City.all
end
def show
find_city
end
def new
#city = City.new
end
def edit
find_city
end
def update
find_city
if #city.save
redirect_to city_path(#city)
else
render "edit"
end
end
def create
#city = City.new(city_params)
if #city.save
redirect_to index_path
else
render "new"
end
end
private
def find_city
#city = City.find(params[:id])
end
def city_params
params.require(:city).permit(:name, :icon_url)
end
end
Routes
get "/cities/new" => "cities#new", as: "new_city"
post "/index" => "cities#create"
get "/cities/:id" => "cities#show", as: "city"
get "/cities/:id/edit" => "cities#edit", as: "edit_city"
patch "/city/:id" => "cities#update"
Form (error is raised on first line)
<%= form_for #city do |f| %>
<% if #city.errors.any? %>
<div class="errors">
<ul>
<% city.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label "Name:" %>
<%= f.text_field :name, class: "form-control" %>
<%= f.label "Icon:" %>
<%= f.text_field :icon_url, class: "form-control" %>
<%= f.submit "PoĊĦalji" %>
<% end %>
When you use form_for #city, and #city is a new record, form_for will try to find a cities_path to POST the new attributes back to.
You should be using resources :cities in your routes file to automatically define the routes and their names. If you want to define a limited set of routes, you can use :only or :except:
resources :cities, only: %i(new create show edit update)
If you don't use resources, you either need to explicitly specify a path for your form_for call, or you need to provide a route named cities_path manually:
post "/index" => "cities#create", as: :cities
Note that index routes don't typically actually contain the word index, you should really just be posting to /cities, not /index.
post "/cities" => "cities#create", as: :cities
I'm trying to render a text area on a user's profile page to allow them to create a post. At the moment I can view all of a user's posts, but I can't get to their profile page because the form will not render.
I did try to changing some stuff around, but then the form would not post due to a routing error.
I feel like I'm posting to the wrong path but I'm not sure so and advice would be appreciated.
class PostsController < ApplicationController
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Posted!"
redirect_to root_url
else
flash[:notice] = "Post could not be submitted"
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit(:user_id, :content)
end
end
_post_form.html.erb
<%= form_for :post, user_posts_path, {method: "create"} do |f| %>
<%= f.text_area :content, size: "60x12", placeholder: "What do you want to say?" %>
<%= f.submit "Post" %>
<% end %>
There's no such HTTP verb called create, you need to change the method mentioned in your form_for, instead of this:
<%= form_for :post, user_posts_path, {method: "create"} do |f| %>
try this:
<%= form_for :post, user_posts_path, {method: "post"} do |f| %>
Please check rake routes and I think you provided the
resources :users do
resources :posts
end
in routes.eb
so
<%= form_for :post, user_posts_path(#user), html: { method: "post"} do |f| %>
in controller
def new
#post = Post.new
#user = current_user
end
I am getting a "No route matches [POST]" when submitting a new form.
### /routes.rb ###
resources :artists, controller: 'artists/artists', only: [:show] do
member do
resources :videos, controller: 'artists/videos', only: [:index, :new, :create, :edit, :update]
end
end
### /artists/videos/videos_controller.rb ###
class Artists::VideosController < ApplicationController
before_action :set_artist
def new
#video = ArtistVideo.new
end
def create
#video = #artist.create_artist_video(video_params)
if #video.save
redirect_to current_artist
else
render 'new'
end
end
private
def set_artist
#artist = current_artist
end
end
### /artists/videos/new.html.erb ###
<%= form_for(#video, url: new_video_path) do |f| %>
<%= f.label :video_title, "title", class: "label" %>
<%= f.text_field :video_title, class: "text-field" %>
<%= f.label :video_description, "decription", class: "label" %>
<%= f.text_field :video_description, class: "text-field" %>
<%= f.label :youtube_video_url, "youtube url", class: "label" %>
<%= f.text_field :youtube_video_url, class: "text-field" %>
<%= f.submit "add video", class: "submit-button" %>
<% end %>
### rake routes ###
videos_path GET /artists/:id/videos(.:format) artists/videos#index
POST /artists/:id/videos(.:format) artists/videos#create
new_video_path GET /artists/:id/videos/new(.:format) artists/videos#new
edit_video_path GET /artists/:id/videos/:id/edit(.:format) artists/videos#edit
video_path PATCH /artists/:id/videos/:id(.:format) artists/videos#update
PUT /artists/:id/videos/:id(.:format) artists/videos#update
So not sure what I'm doing wrong here. I've tried taking :index completely out so videos_path uses the post method, but I still have the same problem.
I'm using the has_many method linking videos to artists, if that even matters.
Not sure if it's the routs or the controller code that's wrong. Any help would be appreciated.
You're specifying a path url: new_video_path but that is for videos#new and what you want is the create path, which is a post to videos_path(#artist). Since it's a nested resource, the path has to have the artist_id which it can get from the #artist instance.
But, the simpler way to do this is like so:
form_for[#artist, #video] do |f|