Redirect_to in Rails 4 - ruby-on-rails

For example I have a controller PostController in RoR 4. and actions in it:
def index
#posts = Post.all.order('created_at DESC')
end
def new
#post = Post.new #second question
end
def create
#post = Post.new(post_params)
post.save
redirect_to #post #first question
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :body)
end
so, the first question is: Why when we write redirect_to #post it automatically redirect to show/id? How rails know, that it must go to show view?
second question: why I must write #post = Post.new in new action? when I comment it, I also can create a Post. What is the deference write it in new action or missing it?
I'm new in rails and there are many magic in it

Q1). This is part of one of main RoR's mantras - convention over configuration. It just assumes, when performing redirect_to #post, you actually want to see the #post resource. The standard REST action of "reading" the resource is show.
But, if - for example - in your view you will do something like
<%= link_to #post.title, #post, method: :delete %>
What will be generated by that will take you to destroy action of #post's resource.
Having conventions like this make you write less code, and - make you happy!
Q2). I'm surprised if what you mentioned worked. It shouldn't, because similar magic is performed in your form_for #post tag in your views. If #post is empty, form_for shouldn't be able to resolve what url to generate, or how to behave in general - depending on Post.new stored in #post it assumes you want to create the resource, and prepare your <form> tag to submit with POST method, but if in #post there is stored already persisted resource, say Post.find(1), it will create the <form> to be submitted with PATCH method.
Again - based on convention, you can write less code, to achieve more.
I strongly advise against omitting something like #post = Post.new. It may lead to hard to identify bugs, even if it worked for you at the moment
Hope it clarifies things!
Good luck!

First questions: it redirects you to the show page using the url_for method (you can read its source if you are curious), remember that #book has an id so it takes that id and includes it in the url of the /books/:id
Second question : you need #post for when you submit an invalid form, then #post will be populated with the errors and displayed on the new page. try to submit an invalid post, you will get complains about a not defined method.
to display the errors of an invalid submission :
<%= form_for :post posts_path do |f| %>
<% if #post.errors.any? %>
See how we used #post above? just to get the errors in it.

When passing a record to redirect_to the url will be generated by calling url_for, which will return a named url for that record. For this it uses the class name for lookup. So passing the Post record will attempt to use the post_path route with the original record as parameter which will resolve in /posts/:id.

First question
Rails magic.
As you pass an ActiveRecord object to redirect, the restful routing interprets this as you wanting to go to the show page of that object.
Plenty of different ways to use redirect_to here.
Second question
Usually #post = Post.new is required as you reference #post in the new action as your forms when constructed with form_for .. useful for validation and dealing with errors.
Technically you could use a form_tag and define Post.new right there in the form. This would mean the #post = Post.new is redundant and works when you comment it out. This way would mean you have no way to pass your objects errors back to the user on the new page though.

Related

Not updating attribute in my rails app

I have creating a web application using Ruby on Rails but now I'm troubling a issue which is post updating, I'm trying to solve this issue which followed this also this. Below is my code:
def update
#edit = Post.find(params[:post_id])
params.permit!
if #edit.update_attributes(params[:post])
redirect_to home_path
flash[:notice] = "Your post updated"
else
flash[:notice] = "Wrong"
end
end
When I use this code then showing
When assigning attributes, you must pass a hash as an argument.
After that
def update
#edit = Post.find(params[:post_id])
params.permit!
if #edit.update_attributes(update_params)
redirect_to home_path
flash[:notice] = "Your post updated"
else
flash[:notice] = "Wrong"
end
end
private
def update_params
params.require(:post).permit(:title, :details, :summery)
end
When I use this then showing
param is missing or the value is empty: post
Where is my actual fault?
It's your form that is causing this error. It means that you aren't passing the values nested inside post. If you view your params (raise params.inspect) you'll be able to see that post doesn't exist.
If you use form_for (or simple_form or formtastic) this is handled for you, but if you are using form_tag or manually creating a form with HTML, or submitting data via ajax you need to add this.
In ajax, you can add by serializing the data before submitting - in a form_tag you can do it this way:
form_tag post_path(#post)

Why does passing this object through redirect_to call the `show` action?

def create
#article = Article.new(params[:article])
#article.save
redirect_to #article
end
def show
#article = Article.find(params[:id])
end
I'm following the Getting Started with Rails guide. I have a form that, upon clicking the submit button, creates an #article object (a RESTful object) with the form input.
redirect_to #article sends a GET request to /articles/id, right? If so, why does this happen? Is this simply how redirect_to works?
redirect_to calls url_for if the argument passed is a Record.
url_for calls to_param on record which by default returns id.
Hence redirect_to #article will generate /articles/:id
Objects
To add to Nishu's answer, when you reference an object in any path_helper (link_to, redirect_to etc), Rails will do the hard work and show you the route for the object
Remember, Ruby / Rails is an object-orientated framework, meaning everything you do has to revolve around an object. In the case of Rails, objects are populated with data from your models, which is done using ActiveRecord
--
So if you use redirect_to #article, Rails will basically look for the show action for that particular record. As your routes should be resourceful - meaning Rails can basically look for the relevant route to display that record on its own
Hope this helps?

Ruby on Rails - Forbidden Attributes on params?

Im trying to redirect someone after they click a button and I keep getting the following error:
ActiveModel::ForbiddenAttributesError
Extracted source (around line #20):
It is throwing the error on the #post = Post.new line.
def create
#post = Post.new(params[:post])
if #post.save
redirect_to posts_path, :notice => "Your post was saved"
I am very new to Ruby and at the moment I am very confused of what this means. I am just following a tutorial and mine isnt working. If anyone could help that would be awesome :D
#post = Post.new(params[:post])
... is no longer used in the latest versions of rails. The problem is that it provided weak security. Someone who was updating their user profile (for example) could theoretically insert an attribute like "administrator: true" to change themselves into an administrator (if that's how admin flag is stored)
Strong parameters now require that you explicity specify which attributes you want to allow to be entered.
So nowadays we do...
#post = Post.new(post_params)
And we have a method later in the controller that specifies the permitted attributes, and looks like...
def post_params
params.require(:post).permit(:title, :body)
end
While I don't have quite enough of your code to specifically answer the question, I can probably get pretty close (minus some column/attribute naming). With strong_params now the standard for Rails applications, you'd probably be looking to do something more like:
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_path, :notice => "Your post was saved"
else
#other stuff here
end
end
private
def post_params
params.require(:post).permit(:content, ....etc) #I took a guess at the attributes you are passing through your params on the create.
end
For a little extra easy-reading on the history/reason: http://blog.8thlight.com/will-warner/2014/04/05/strong-parameters-in-rails.html
Let me know if you'd like any additional clarification.

Ruby on Rails: How to save a model that is dependant on two others?

I am fairly new to Ruby on Rails. I have set up a basic User / Post Model which allows a User to create Posts. I am trying to create Comments for the Posts, which will also relate a Comment to the User who created it.
I have set up the relationships so that a User has many Posts and Comments, a Post belongs to a User and has many Comments, and a Comment belongs to both a Post and a User.
My problem comes in when trying to save a Comment. In my Comments controller:
def create
#comment = current_user.comments.build(params[:comment])
end
This does not work and says nothing about which Post the Comment belongs to. I am also displaying the 'Add Comment' form on the Show Posts page in order to create a Comment Wall below the Post, but my form still just says
<%= form_for #comment do |f| %>
And does not relate the comment to the Post in the Posts controller under Show.
I realize there is probably a straightforward answer but could not find any resources that explained my specific issue. Any help is appreciated.
I would say that you're primarily adding the comment to a specific post. So start there:
def create
#post = Post.find(params[:post_id]) # <== this may be just `id`
#comment = #post.comments.build(params[:comment])
#comment.user = current_user
if #comment.save
# ... do things
else
# .. render error
end
end
For this to work you're going to need your route to be nested:
resources :posts do
resources :comments
end
And your form_for will need to indicate the nested route:
<%= form_for [#post, #comment] %>
You are doing the right thing in CommentsController#create
#comment = current_user.comments.build(params[:comment])
The part that you're missing is include the post_id in your params[:comment]. That should be no problem because you always know the post you're commenting on, the one that you're showing. So add the following inside your form_for #comment
<%= f.hidden_field :post_id, #post.id %>
I am assuming this is in your show post view, and you have set #post in your PostController#show
You can do:
def create
#comment = Comment.new(params[:comment])
#comment.user = current_user
if #comment.save ...

Rails - How does ActiveRecord's save method work?

A newbie question regarding the ActiveRecord's save method.
If i have this code (as in rails guide):
def create
#post = Post.new(params[:post])
if #post.save
redirect_to #post
else
.....
end
end
The save method returns the new created Post object? How, after the code #post.save, rails know how to substitute the redirect_to #post with the proper post_id (1 or 2 or 3 or ....) to build the link?
It's an OOP concept.
So, after create, the #post is updated with the id, and everything just works.
Take a look at this code.
Hope it helps.
I'm going to explain it by presenting another piece of code that should make things easy to understand
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user
Now :user contains the following information based on the User model: id, name, email, telephone.
So that means we have actually assigned to #user the above hashes.
The redirect_to will retrieve the hashes that is already stored in #user and display the new profile page.
I hope it helped.

Resources