undefined method `[]' for nil:NilClass when user unfollows project - ruby-on-rails

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 %>

Related

Rails input data not working between pages

I want to made a page that shows you what you introduced in the text box after you pressed the button this is my code. What is wrong? Thanks.
routes.rb
Rails.application.routes.draw do
get '/page' => 'pages#page'
post '/act/' => 'pages#act'
pages_controller.rb
class PagesController < ApplicationController
def page
#input = params[:field1]
end
def act
#input = params[:field1]
redirect_to '/page'
end
end
page.html.erb
<%= form_tag( {:controller => :pages, :action => 'act' }, :method => "post") do %>
<%= text_field_tag :field1 %>
<%= submit_tag "Show text-box contents" %>
<% end %>
<br>
<p> Your input is </p>
<br>
<%= #input %>
def act
render :page
end
instead of redirect_to '/page' will work.
but this is not the rails way of doing.
Please see Rails guide for better controllers .
You can remove #input = params[:field1]
in routes.rb you can just use
resources :pages
run rake routes in console
You can see all the inbuild routes rails give you.
In your case def page should be def new
and def act should be def create
Your page.html.erb should be changed to new.html.erb
<%= form_for #input, url: {action: "create"} do %>
<%= text_field_tag :field1 %>
<div><%= submit_tag 'Save' %></div>
<% end %>

How to solve undefined method `to_key' error with collection_select - RoR

I'm trying create a collection select, but I got this error:
NoMethodError in Deal#selectuser
undefined method `to_key' for #<Conversation::ActiveRecord_Relation:0x1059f4f8>
My controller
def selectuser
#conversation = Conversation.involving(current_user)
end
My routes
resources :deal, only: [:index, :new, :create, :selectuser] do
collection do
get "selectuser" # generate get "/deal/selectuser"
end
My view (conversation.html.erb)
<%= form_for #conversation do |f| %>
<%= collection_select(:conversation, :recipient_id, Conversation.all, :recipient_id, :title) %>
<%= f.submit "Send", class: "btn btn-primary wide" %>
You need to write the collection_select method as:
<%= f.collection_select :recipient_id, Conversation.all, :recipient_id, :title %>

In rails, how to create forms for routes which are members of a resource?

I want to create a form for "Comments" route which is a member of Article Resources:
resources :articles do
member do
post 'comments'
end
end
I want the comment form to be in Articles#Show page. The problem i got an error:
First argument in form cannot contain nil or be empty
If the for is like this:
<div>
<%= form_for #comm do |c| %>
<%= c.label :Your_comment %>
<%= c.text_area :commBody %>
<%= c.submit 'submit' %>
<% end %>
</div>
So how to do it ?
If this is your controller,
def show
#article = Article.find(params[:id])
end
and you want to create a form for a new Comment related to #article that points to POST /articles/3/comments:
<%= form_for([#article, Comment.new], as: :article, url: comments_article_path(#article)) do |f| %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit 'Submit' %>
<% end %>
Don't forget to add accepts_nested_attributes_for :comments in the Article model. And also don't forget to setup the whitelisted params in the ArticleController.
Another thing: don't use abbreviations for your variable names. Use #article and #comment, not #art and #comm.
#config/routes.rb
resources :articles do
post :comment, on: :member #-> url.com/articles/:id/comment
end
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def show
#article = Article.find params[:id]
#comment = #article.comments.new
end
end
#app/views/articles/show.html.erb
Comment:
<%= form_for [#article, #comment], url: article_comment_path(#article) do |c| %>
<%= c.label "Your Comment" %>
<%= c.text_area :commBody %>
<%= c.submit %>
<% end %>

Form inside a loop how to do it the Rails way?

Hi I have a working "blog module" on my page.
From the start. My routes looks like this:
root 'static_pages#home'
resources :announcements, only: [:new,:create,:update,:edit,:destroy,:show] do
resources :comments, only: [:create, :destroy]
end
My controller actions looks like this:
static_pages_controllers.rb
def home
#announcements = Announcement.page(params[:page]).order('id DESC')
end
announcements_controller.rb
def new
#announcement = Announcement.new
end
def create
#announcement = Announcement.new(announcement_params)
if #announcement.save
flash[:success] = "Post został pomyślnie dodany"
redirect_to root_path
else
render 'new'
end
end
comments_controller.rb
def create
#announcement = Announcement.find(params[:announcement_id])
#comment = #announcement.comments.new(comments_params)
if #comment.save
flash[:success] = "Komentarz dodano"
redirect_to root_path }
else
render 'staticpages#home'
end
end
Part of the home.html.erb which lists all anouncements and under each of them it adds a form to add a comment:
<% #announcements.each do |announcement| %>
.... some code ....
<% if current_user && user_signed_in? %>
<div class="create_comment" >
<%= render partial: 'shared/create_comments_form', locals: {announcement: announcement } %>
</div>
<% end %>
... some code ...
<% end %>
And _create_comment.html.erb :
<%= form_for announcement.comments.create, url: announcement_comments_path(announcement.id) do |form| %>
<%= form.label :author, "#{current_user.username}:" %>
<%= form.hidden_field :author, value: current_user.username %>
<%= form.hidden_field :user_id, value: current_user.id %>
<%= form.text_field :content, class: "form-control content_length" %>
<div class="char_counter">255</div>
<%= form.submit "Dodaj!", class: "btn btn-primary" %>
<% end %>
My question is there a better way of writing this form, because It just doesn`t look rails for me when I have to specify everywhere all those parameters. Eg. when I send parameters to _create_comment I have to pass announcement object, and in form it self I have to specify the url as it looks for create_comment_path by default.
I think you wanted just to handle nested resources, and need a form to create such a nested resource.
Then this should work:
form_for( [announcement, announcement.comments.new] ) do |form|
Do not use create in the form template, as it actually saves it to the database, you end with lots of empty comments just because somebody viewed the form.
You can use cokoon gem for this. This gem will create Dynamic nested forms using jQuery.
Also I have one more suggestion. Rather then using only you can use except. Because you have used all 6 routes without index.
root 'static_pages#home'
resources :announcements, except: [:index] do
resources :comments, only: [:create, :destroy]
end
Update:
You can use like below:
Form:
<%= form_for :comments do |form| %>
<%= form.label :author, "#{current_user.username}:" %>
<%= form.hidden_field :author, value: current_user.username %>
<%= form.hidden_field :user_id, value: current_user.id %>
<%= form.text_field :content, class: "form-control content_length" %>
<div class="char_counter">255</div>
<%= form.submit "Dodaj!", class: "btn btn-primary" %>
<% end %>
For more info: http://www.sitepoint.com/complex-rails-forms-with-nested-attributes/

No route matches [POST] "/organizations/new"

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' %>

Resources