In my rails app I got quite a few resources and have created a few forms already - but for some reason I don't seem to get one specific form for a new object to work. I am not sure if it is because I am using a three-way has_many :through relationship or because I am just overlooking something else
Here's how my routes looks like
resources :users, shallow: true do
resources :organizations, :notifications
end
resources :organizations, shallow: true do
resources :plans, :users, :notifications
end
My organizations_controller looks like this:
def index
#user = current_user
#organizations = #user.organizations.to_a
end
def show
#user = current_user
#organization = Organization.find(params[:id])
end
def new
#organization = Organization.new
end
def create
#user = current_user
#organization = Organization.new(organization_params)
#organization.save
redirect_to #organization
end
On my organizations index page I link to this:
<%= button_to 'New Organization', new_organization_path, :class => 'btn btn-primary' %>
which should lead to my new.html.erb:
<%= form_for (#organization) do |f| %>
<%= render 'layouts/messages' %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :website %>
<%= f.text_area :website, class: 'form-control' %>
</div>
<%= f.button :class => 'btn btn-primary' %>
<% end %>
Every time I click on "new Organization" I get following error:
No route matches [POST] "/organizations/new"
Which is correct - I do not have a new_organizations_path that accepts POST requests. I know I can manually change the method of the form to GET but shouldn't it work the way I did it? I have another form that follows the same principle just for a different resource and it works perfectly.
Thanks for your help in advance!
button_to would always send a POST request unless something else is specified.
On the other form, you must be using link_to and not button_to which is why its working there.
You can change the button_to in two ways, pick the one that suits you:
Option 1: Use link_to
<%= link_to 'New Organization', new_organization_path, :class => 'btn btn-primary' %>
Option 2: Use button_to with method: :get
<%= button_to 'New Organization', new_organization_path, method: :get, :class => 'btn btn-primary' %>
Related
So currently i have a link_to, where signed in users can click on:
<%= link_to "Enroll", [#task.project, #task] %>
The user has an association with the project, through subscription. To create a new subscription for a user with a project, i wrote some simple form for it.
<%= form_for([#project, #subzz]) do |f| %>
<%= f.hidden_field :project_id, :value => #project.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Which works fine and creates the association. However, i want that the user is able to create the subscription whenever he clicks on 'enroll' instead of a second, extra submit button.
Any ideas how to approach this? I thought about using jQuery, but not sure how to inject the ids with it and if its the 'right' way to do it.
Thanks in advance everyone!
EDIT:
When using the method posted as answer, i get:
param is missing or the value is empty: sub
My updatet form:
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<%= hidden_field_tag :user_id, :value => current_user.id %>
<%= link_to "Enroll", [#task.project, #task], :onclick => "$('#project_form').submit() "%>
<% end %>
subs_controller.rb
class SubsController < ApplicationController
def create
#subz = Sub.create(sub_params)
project = #subz.project
redirect_to root_path
end
private
def sub_params
params.require(:sub).permit(:project_id, :user_id)
end
end
You can be using the existing form and link_to, just edit some like edit the dorm_tag like this
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
and remove the button into form like this one
<div class="actions">
<%= f.submit %>
</div>
and edit the link_to like this
<%= link_to 'Enroll', "", :onclick => "$('#project_form').submit()" %>
it will work
Update
You can achieve this without a form, comment out this form and edit the link like below
<%= link_to 'Enroll', subs_path(project_id: #project.id, user_id: current_user.id), method: :post %>
and the create method update like below
def create
#subz = Sub.new(sub_params)
if #subz.save
flash[:success] = 'Sub was successfully submited.'
redirect_to root_path
else
flash[:danger] = 'Sub not submited'
redirect_to request.referer
end
end
that is easier
Or if you keep before one with form then the link out from the form and the create method edit like the following
def create
#subz = Sub.new(sub_params)
if #subz.save
flash[:success] = 'Sub was successfully submited.'
redirect_to root_path
else
flash[:danger] = 'Sub not submited'
redirect_to request.referer
end
end
and the form will look like this
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<%= hidden_field_tag :user_id, :value => current_user.id %>
<% end %>
<%= link_to "Enroll", [#task.project, #task], :onclick => "$('#project_form').submit() "%>
if you confused this [#task.project, #task] on link tag then use direct link
So i came up with the following solution:
I've added the sub handling to the application_controller, so that its availiable for the project_controller. I also added the project, tasks as a reference, so that i am able to redirect to a task via the sub_controller, instead of the project_controller.
application_controller.rb
def create
#subs = Sub.new(sub_params)
project = #subs.project
taskz = project.tasks.first
if #subs.save
redirect_to [taskz.project, taskz]
end
end
private
def sub_params
params.require(:sub).permit(:project_id, :user_id)
end
Inside the show.html.erb from the project_controller, i use the old form:
<%= form_for([#project, #subz] do |f| %>
<%= f.hidden_field :project_id, :value => #project.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.submit "Submitted" %>
<% end %>
which works fine. Thanks for any previous help!
I am having issues getting my create method to function correctly.
Here is my new.html.erb file
<div class="col-md-8">
<%= form_for #wiki do |f| %>
<%= f.label :title, class: 'form-control' %>
<%= f.text_field :title, class: 'form-control', placeholder: "Enter wiki title" %><br><br>
<%= f.label :body, class: 'form-control'%>
<%= f.text_area :body, class: 'form-control', placeholder: "Enter wiki body" %><br><br>
<%= f.check_box :private %> Private Topic<br><br>
<%= f.submit "Save", class: 'btn btn-success' %>
<% end %>
</div>
Controller
def new
#wiki = Wiki.new
end
def create
#wiki = Wiki.create(params[:wiki])
if #wiki.save
flash[:notice] = "Wiki has been saved"
redirect_to wiki_index_path
end
end
private
def wiki_params
params.require(:wiki).permit(:title, :body, :private)
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :wiki
post 'wiki/new'
post 'wiki/create'
resources :users
root 'welcome#index'
end
If I use :wiki in my form_for on new.html.erb I can get passed the error but when clicking on my save button on the actual new page, nothing happens at all (since I'm not saving the information to the correct variable). However, as soon as I use the #wiki variable, I get the error
"undefined method `wikis_path' for #<#<Class:0x007f8f794e5d58>:0x007f8f7bb2ef50>"
Any help is appreciated!
You can get rid of redundant unrestful wiki routes. resources :wikis will be enough:
Rails.application.routes.draw do
devise_for :users
resources :wikis
resources :users
root 'welcome#index'
end
And something tells me that all will be fine after that change.
I got a modal, with a form inside it. However I get the classic error when I try to submit:
Couldn't find User without an ID
My form looks like this:
<%= form_for add_email_users_path, url: { action: 'add_email', controller: 'users' } do |f| %>
<%= f.email_field :email, placeholder: 'Your email address', class: 'input-lg form-control' %>
<%= f.button 'Continue', class: 'btn btn-success', 'data-disable-with' => "Saving <i class='fa fa-spinner fa-spin'></i>".html_safe %>
<% end %>
routes:
resources :users, except: [:destroy] do
post 'add_email', on: :collection
end
User_controller:
def add_email
#user = User.find(params[:id])
if #user.update_attributes(setup_params)
redirect_to campaigns_path, notice: 'Thank you for adding your email!'
else
redirect_to :back, alert: 'Unable to save your email'
end
end
Try this:
<%= form_for add_email_users_path(#user) do |f| %>
<%= f.email_field :email, placeholder: 'Your email address', class: 'input-lg form-control' %>
<%= f.button 'Continue', class: 'btn btn-success', 'data-disable-with' => "Saving <i class='fa fa-spinner fa-spin'></i>".html_safe %>
<% end %>
and your route:
resources :users, except: [:destroy] do
post 'add_email', on: :member
end
You have the wrong path method in your form_for, it should be:
add_email_user_path(#user)
And your route should be for member not collection:
post 'add_email', on: :member
Here is what your stuff should look like:
form.html.erb
<%= form_for add_email_user_path(#user) do |f| %>
<%= f.email_field :email, placeholder: 'Your email address', class: 'input-lg form-control' %>
<%= f.button 'Continue', class: 'btn btn-success', 'data-disable-with' => "Saving <i class='fa fa-spinner fa-spin'></i>".html_safe %>
<% end %>
routes.rb
resources :users, except: [:destroy] do
post :add_email, on: :member
end
Take special note of the change to the form_for call.
It can't be a collection method as it is looking for specific id define it as a member method
resources :users, except: [:destroy] do
member do
post :add_email
end
end
In form
<%= form_for add_email_user_path(#user), method: :post do |f| %>
You can refer to this docs to understand member and collection methods
i have some problems with my app, i have posts, posts has_many responces
when i create new responce to the post, not added in the db 'responce' post_id
my routes.rb
resources :categories do
resources :posts
end
resources :posts do
resources :responces
end
controller
class ResponcesController < ApplicationController
def new
#post = Post.find(params[:post_id])
#responce = #post.responces.new(post_id:params[:post_id])
end
def create
#responce = current_user.responces.build(responce_params)
#post = Post.find(params[:post_id])
if #responce.save
flash[:success] = "Вы откликнулись на задание"
redirect_to post_path #post
else
render 'new'
end
end
def show
end
private
def responce_params
params.require(:responce).permit(:price, :comment, :post_id)
end
end
view
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
but if add to the view this
<%= f.collection_select :post_id, Post.all, :id, :name %>
rails create post_id to the db
help
You are doing several things the wrong way.
First: I don't think you need two separate resources for the same model. I'd recomend nesting all three resources upon each other like this.
resource :categories do
resource :posts do
resource :responces
end
end
This way you'll be able to find the needed category_id and post_id in the params hash.
I'd also recomend adding :shalow => true to the :categories resource to make your routes a bit prettier.
Second: you need to assign the params[:post_id] in your create action, like this.
#responce = current_user.responces.build(responce_params)
#responce.post_id = params[:post_id]
#post = #responce.post
Alternatevely you can just add a hidden field to your form like I show below, but it I don't like that approach, 'cause it can lead to security risks.
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.hidden_field :post_id, :value => #post.id %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
In your form you aren't passing in the post_id. You probably want something like this:
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.hidden_field :post_id, :value => #post.id %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
The hidden field will pass the id of the current post into your form as the post_id parameter.
In my app users can follow projects. I've been following Michael Hartl's guide on following users and adapting it along on the way for following projects.
I've currently got follow working but when I click unfollow I get this error:
undefined method `[]' for nil:NilClass
about the following part in my Follows controller:
def get_followed_project
#project = Project.find(params[:follow][:followed_id])
end
The rest of the destroy action is:
def destroy
current_user.unfollow_project!(#project)
redirect_to #project
end
The form partials for following and unfollowing are:
<%= form_for current_user.follows.build(:followed_id => #project.id) do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "Follow", class: "button" %>
<% end %>
<%= form_for current_user.follows.find_by_followed_id(#project), :html => { :method => :delete } do |f| %>
<%= f.submit "Unfollow", class: "button" %>
<% end %>
These methods are in my User model:
def follow_project!(project)
follows.create!(:followed_id => project.id)
end
def unfollow_project!(project)
follows.find_by_followed_id(project).destroy
end
I have this in my routes.rb:
resources :follows, only: [:create, :destroy]
and this:
resources :users do
member do
get :following, :followers
end
end
I've found if I bypass the before_action for destroy and instead put this at the start of the action:
#project = Follow.find(params[:id]).followed_id
it works, but then this fails:
redirect_to #project
I'm not entirely sure why that line works but I'd rather get it working as per the guide, any ideas?
When you click "Unfollow", this form hasn't a field named "followed_id" and your form hasn't any inputs, so params[:follow][:followed_id] will throw an error, add f.hidden_field :followed_id to your form:
<%= form_for current_user.follows.find_by_followed_id(#project), :html => { :method => :delete } do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "Unfollow", class: "button" %>
<% end %>