data travelling between controller and embedded ruby file(ruby on rails) - ruby-on-rails

I'm just beginning to learn Ruby on Rails. One thing I'm having real trouble understanding is how data is transferred from the .html.erb file to the controller file.
Consider the following new.html.erb
<%= form_for :post, url: posts_path do |f| %>
<p>
<%=f.label :title %>
<%=f.text_area :title %>
</p>
<p>
<%=f.label :body %>
<%=f.text_area :body %>
</p>
<p>
<%=f.submit %>
</p>
<% end %>
and then there's my controller file, posts_controller.rb
class PostsController < ApplicationController
def index
#post=Post.all
end
def new
end
def create
#post=Post.new(post_param) #
#post.save
redirect_to #post
end
def show
#post=Post.find(params[:id])
end
private
def post_param
params.require(:post).permit(:title, :body)
end
end
Okay now so the part that I don't understand.
How does the create method get the value for 'post'.
Can you explain what <%= form_for :post, url: posts_path do |f| %> actually does?

form_for sends an http POST request directed at the posts_path.
Your routes file probably says something like "resources :post", which
automatically directs any http POST requests to the "create" method in your controller.
Inside this POST request, all the data you entered into the form will be inside the params variable.

Related

Wrong number of arguments error (0 for 1) in Ruby on Rails 4 when creating a form for user submission

at the moment I am attempting to create a form for my website that will allow for users to input information and then the information with be POST'ed to my database for storage. I am a new ruby on rails developer so keep that in mind.
I was able to get to the point where the user could see the form and type in information but once they hit the submit button I recieve an error, and that error is
ArgumentError in StudentsController#create
wrong number of arguments (0 for 1) in app/controllers/students_controller.rb:13:in `create'
The parameters that were sent were the following
{"utf8"=>"✓",
"authenticity_token"=>"bLalQ9Ek5ziaGiGHj03AGPCTIABAgcT+o4eTgN44qv44dxNDlrGA0h2u5BSTQVTMh+YgA/mLPQee05lT7mxCsw==",
"student"=>{"first_name"=>"Andrew",
"last_name"=>"Terra"},
"commit"=>"Submit"}
Below is my students_controller.rb file.
class StudentsController < ApplicationController
def index
#students = Student.all
end
def new
#student = Student.new
end
def create
#student = Student.new(params.require[:student])
if #student.save
redirect_to students_path
end
end
def destroy
#student = Student.find_by_id(params[:id])
if #student.destroy
redirect_to students_path
end
end
end
Below is my views/students/_form.html.erb file
<%= form_for #student do |f| %>
<p>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</p>
<%= f.submit "Submit" %>
<% end %>
Below is my /views/students/index.html.erb file
<%= link_to "Create new information", new_student_path %> <br /> <hr>
<% #students.each do |fo| %>
Firstname: <%= fo.first_name %> <br />
Lastname: <%= fo.last_name %> <br />
<%= link_to "Delete info?", student_path(student), :data=>{:confirm=>"Are you sure ?"}, :method=> :delete %>
<br />
<hr>
<% end %>
Finally, here is my /views/students/new.html.erb file
Enter new info
<hr>
<%= render :partial => "form" %>
And I did remember to put resources :students in my routes file. I searched around and found other people who had previously had this problem but none of the solutions worked on the code that I have written. So I was wondering if anyone could point me in the direction of where the bug is and how exactly I can fix it. Thank you.
You need to add a new private method:
private
def student_params
params.require(:student).permit(:first_name, :last_name)
end
And then as said before change your create method to:
def create
#student = Student.new(student_params)
if #student.save
redirect_to students_path
end
end
I recommend reading the documentation on Strong Parameters - to better understand how they work. https://github.com/rails/strong_parameters
You have to change
params.require[:students] to params.require(:students)
But this is still not good way to handle your params for create action, you should add private method student_params to your controller where you would whitelist your params. Like this:
def student_params
params.require(:student).permit(:first_name, :last_name)
end
Here you can find more about it,
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Connecting routes, views and controllers (Rails)

I'm learning Rails so please pardon my amateur mistakes, but I've been stuck for about an hour or two and have made negative progress.
Goal:
From the user profile view, link to a form that allows this user
to change their email. Once the form is submitted, it should trigger
an appropriate method within the user controller.
I can handle the rest, I just haven't managed to connect the parts mentioned above. I have been reading railsTutorial.org and guides.rubyonrails.org but haven't been able to understand routing form_for() sufficiently.
User Profile Link:
<%= #user.email %> <%= link_to "(change)", email_path(#user) %>
Routes
Rails.application.routes.draw do
get 'email' => 'users#email_form'
post 'email' => 'users#changeemail'
end
User Controller
class UsersController < ApplicationController
def email_form
#user = User.find(params[:id])
end
def changeemail
#user = User.find(params[:id])
redirect_to #user
end
end
Currently the error I get once I click the link is Couldn't find User with 'id'= which I assume means user ID is nil because I fail at passing it.
I would greatly appreciate an explanation of what data is being passed through this workflow so I can be a better developer, thank you very much!
EDIT:
The form itself:
<%= form_for(#user, url: user_path(#user)) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :new_email %>
<%= f.text_field :new_email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.submit "Submit New Email", class: "btn btn-primary" %>
<% end %>
You could do this (note :id and "as"):
Rails.application.routes.draw do
get 'email/:id' => 'users#email_form', as :email
post 'email/:id' => 'users#changeemail', as :change_email
end
The :id is then expected to be part of the route.
Alternatively, pass the id directly when generating the url:
<%= #user.email %> <%= link_to "(change)", email_path(id: #user) %>
This will make a call to "UsersController#update"
<%= form_for(#user, url: user_path(#user)) do |f| %>
...instead you would use something like::
<%= form_for(#user, url: change_email_path(#user), method: :put) do |f| %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
...but in terms of best practices, if you want to do separate flow for email updating, you could be more explicit in treating it as a different resource (even though it's still the user record).
For example, you could map these to an explicit 'resource' with a #show and #update action...
Routes:
resources :user_emails, only: [:show, :update]
Controller:
class UserEmailsController < ApplicationController
def show
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
redirect_to #user # goes back to UsersController#show
end
end
Then the route would be:
<%= #user.email %> <%= link_to "(change)", user_email_path(#user) %>
In this case we don't have to say (id: #user) since the 'resource' generates the right urls for you.
...and this would be
<%= form_for(#user, url: user_email_path(#user), method: :post) do |f| %>

Form resulting in blank post with no ID

I am new to Rails and working on creating a generic "facebook" type of app as practice with users and posts associated with each user. However, I'm currently having an issue where I think the form that I am using to create the posts is also being rendered out as a blank post with no post ID where I display all of the posts in a section below. I think that this post is being shown even before it is being saved to the database.
Here is my code in my view:
<div class="newpostcontainer">
<div class="newposttext">
<%= form_for([#user, #user.posts.build]) do |f| %>
<%= f.text_area :post, size: "69x1" %>
</div>
<div class="newpostsubmitbutton">
<%= f.submit %>
</div>
<% end %>
</div>
<% #user.posts.reverse_each do |p| %>
<div class="postedcontainer">
<div class="minipostpic">
<%= image_tag #user.photo.url, width: 32, height: 32 %>
</div>
<div class="nameofposter"><%= #user.name %></div>
<div class="dateofpost"><%= p.created_at%></div>
<div class="postcontent"><%= p.id%></div> <br>
<div class="postcontent"><%= p.post%></div> <br>
<div class="likecommentdelete">
<%= link_to "Delete", [p.user, p], method: :delete %> | Like | Comment
</div>
</div>
<%end%>
</div>
Here is my controller:
def index
#user = User.find(params[:user_id])
#posts = #user.posts.all
end
def create
#user = User.find(params[:user_id])
#post = #user.posts.create!(post_params)
redirect_to user_path(#user)
end
def show
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
redirect_to user_path(#user)
end
def destroy
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
#post.destroy
if #post.destroy
redirect_to user_path(#user)
else
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit!
end
end
And here is my model:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates_presence_of :post
end
I'm pretty sure the issue has something to do with my form to create the new post because when I remove it or comment it out, the extra blank post with no post ID goes away.
Any thoughts or suggestions?
Thank you!!
I think you need to permit the field values to be posted:
i.e.,
params.require(:post).permit!
should be
params.require(:post).permit(:name, :post)
then only it will POST I think.
Hope it helps :)
This is because of rails 4 strong parameter feature. You need to whitelist your active models parameters. For more details refer to here.
In your case you need to do something like this:
params.require(:post).permit(:post)
where the ":post" inside require is your model and the other one is your permitted field that is your textarea.
Several issues -
Form
<%= form_for([#user, #user.posts.build]) do |f| %>
Why are you building an associative object? #user.posts.build will not persist your data, and will cause all sorts of non-conventional issues I would highly recommending building the posts associative object in your controller's new action before using in the view, so you can do this:
#app/controllers/users_controller.rb
def new
#user = current_user
#user.posts.build
end
<%= form_for #user do |f| %>
Association
You're trying to edit the post attribute with this statement:
<%= f.text_area :post, size: "69x1" %>
This won't work in any circumstance, as :post is an association, not an object. Rails only allows you to change / add attributes to specific objects, which means you'll be better doing something like this:
<%= f.fields_for :posts do |p| %>
<%= p.text_area :title %>
<%= p.text_area :body %>
<% end %>
Strong Params
You're currently permitting all your params? You'll be better doing this:
def post_params
params.require(:user).permit(posts_attributes: [:title, :body])
end
Use Posts Controller
A better way will be to just use the posts_controller, like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
end
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<% end %>

No route matches [POST] "/companyrating/index"

I am newbie to ruby on rails. I am getting this error. I have followed this tutorial http://www.codelearn.org/ruby-on-rails-tutorial/forms-form_tag-params-attr_accessible-model-validation
for the form posting. But when I click on submit i was getting an error
this is my
controller
class CompanyratingController < ApplicationController
def index
#companies = Companyrating.all
end
def add
#companies.create(:companies => params[:name, :place, :rate, :rank])
#redirect_to :action => 'index'
#companies = Companyrating.new(params[:name])
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
end
end
end
this is modal
class Companyrating < ActiveRecord::Base
attr_accessible :name, :place, :rate, :rank
end
this is my routes file
get "companyrating/index"
match "companyrating/add" => "todos#add", :via => :post
my index file
<title>Shared Todo App </title>
<h1>Shared Todo App</h1>
<p>All your todos here</p>
<ul><li> <% #companies.each do |t| %>
<li> <%= t.companies_name %> </li>
<li> <%= t.companies_place %> </li>
<li> <%= t.companies_rate%> </li>
<li> <%= t.companies_rank %> </li>
<% end %>
</li></ul>
<%= form_for("#companies/add", :method=>"post") do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :place %>
<%= f.text_field :place %>
<%= f.label :rate %>
<%= f.text_field :rate %>
<%= f.label :rank %>
<%= f.text_field :rank %>
<%= f.label :user_id%>
<%= f.text_field :user_id %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
This was my error: No route matches [POST] "/companyrating/index"
can anyone help me in solving this error
in controller:
def new
#companyrating = Companyrating.new
end
def create
#companies = Companyrating.new(params[:companyrating])
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
else
flash[:error] = "Can't create companyrating."
render 'new'
end
end
in routes.rb:
resources :companyrating
in form:
<%= form_for(#companyrating, method: :post) do |f| %>
The problem you're having is two-fold - with your routes and controller actions
I know Monk_Code gave an answer, but since you're new, I'll explain how it all works for you, with the goal of helping you understand the system a bit better:
Routes
Your first issue is to do with your routes
Rails has done an amazing job of creating great routing structures, and the core of this is the idea of resourceful routes
By using the following code, your Rails app creates a series of 7 routes which Rails uses to send "default" traffic to your controller actions:
#config/routes.rb
resources :companyratings
This routing structure creates the following routes in your app:
new [GET]
index [GET]
create [POST]
edit [GET]
update [POST]
destroy [DELETE]
show [GET]
All of these routes take directed traffic, and routes it to the relevant controller action. This means that if you send a user to /companyratings/, it's going to load the index action, likewise /companyratings/15 will show the show action in the controller
On top of this, you also need to know what the HTTP "verb" does. This is a key principle which Rails uses to route your traffic accordingly. The "verb" in your request is the type of request that's sent, and is dependent on the browser
As you can see from the list above, every route has an associated HTTP verb. The reason why this is important is because if you send a [GET] request to a route which only works with the [DELETE] verb, you're going to get a problem, hence why you're seeing errors when you send a [POST] request to your index action
You should read the Rails tutorial on this, as you can either fix the issue by sending the correct HTTP verb (using :method => :get), or specify the [POST] verb in your index action route
Controller Actions
Controller actions are the function defined in your controller, which are loaded when you run a particular request in Rails
The default index actions are listed above, but you can also have any others you like, as long as you provide the correct routes. Your problem is that you've just used the add action, where you should have used the create action:
class CompanyratingController < ApplicationController
def index
#companies = Companyrating.all
end
def new
#companyrating = Companyrating.new
end
def create
#companies = Companyrating.new(new_company_rating)
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
end
end
private
def new_company_rating
params.require(:company_rating).permit(:variables, :listed, :here)
end
end

Rails 4 Routing Error - no rout matches [POST] "/categories/new"

While learning Rails 4 I stuck while trying to add categories to posts of my simple blog. I have generated model, ran the migration and added a controller. No matter what I do now when trying to create a category, I keep running into same mistake: no route matches [POST], which is weird, as I seem to have all the code in place. Please help!
categories controller
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def new
#category = Category.new
end
def create
#category = Category.new(category_params)
#category.save
redirect_to new_category_path, alert: "Category created!"
end
def show
#category = Category.find(params[:id])
end
def destroy
#category = Category.find(params[:id])
#category.destroy
redirect_to categories_path
end
private
def category_params
params.require(:category).permit(:name)
end
end
routes.rb
Blog::Application.routes.draw do
get 'tags/:tag', to: 'posts#index', as: :tag
resources :categories
resources :posts do
resources :comments
end
root 'welcome#index'
end
category.rb
class Category < ActiveRecord::Base
validates :name, presence: true
has_many :posts
end
new.html.erb
<%= form_for :category do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
/categories/new
No route matches [POST] "/categories/new"
You should have in your view
<%= form_for #category do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
#category object is used by form_for method to figure out form url.
If you pass only Symbol to form_for method, without specifying url explicitly, form will be generated with url being the current url.
Although the #category works, if you read a bit further you will see that they will explain why the your code sends No route matches [POST] "/categories/new".
The guide actually explains that you need to specify the url: posts_path for the form to use the right route.
There's one problem with this form though. If you inspect the HTML
that is generated, by viewing the source of the page, you will see
that the action attribute for the form is pointing at /posts/new. This
is a problem because this route goes to the very page that you're on
right at the moment, and that route should only be used to display the
form for a new post.
The form needs to use a different URL in order to go somewhere else.
This can be done quite simply with the :url option of form_for.
Typically in Rails, the action that is used for new form submissions
like this is called "create", and so the form should be pointed to
that action.
Edit the form_for line inside app/views/posts/new.html.erb to look
like this:
<%= form_for :post, url: posts_path do |f| %>
In this example, the
posts_path helper is passed to the :url option. What Rails will do
with this is that it will point the form to the create action of the
current controller, the PostsController, and will send a POST request
to that route.

Resources