Url changed when submit and surrounding issues - ruby-on-rails

i'm newbie in Ruby on rails.
I'm doing CRUD for Articles and have a question: how to keep url and data's form when i create or update a article but it invalid validate?
And if they resolved, how to keep _form.html.erb to use for create and edit view.
I tried some solution in stackoverflow but there are no solution resolved all my problems above.
Here is new article view:
https://ibb.co/bdm4Hxj
You see, url change from /articles
https://ibb.co/wQ6Vxpz
inspect, we see action: /articles, method: post
https://ibb.co/LPJzvLr
and routes in rails:
https://ibb.co/rs1T1PY
_form.html.erb for create and edit view:
<%= form_for #article, html: {class: "form-horizontal"}, local: true do |f| %>
<div class="form-group">
<%= f.label :title, "Title", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_field :title, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :text, "Text", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_area :text, class: "form-control"%>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-4">
<a class="btn btn-success" href="<%= articles_path %>">Back</a>
<%= f.submit action_name.capitalize, class: "btn btn-success" %>
</div>
</div>
<% end %>
My ArticlesController:
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def new
#article = Article.new
end
def show
#article = get_by(:id)
end
def create
#article = Article.new(article_params)
if #article.save
flash[:success] = 'Create success!'
redirect_to articles_path
else
flash[:warning] = 'Something went wrong!'
render :new
end
end
def edit
#article = get_by(:id)
end
def update
#article = get_by(:id)
if #article.update(article_params)
flash[:success] = 'Update success!'
redirect_to articles_path
else
flash[:warning] = 'Update failed!'
render :edit
end
end
def destroy
#article = get_by(:id)
if #article.destroy
flash[:success] = 'Delete success!'
redirect_to articles_path
else
flash[:warning] = 'Delete failed!'
render :new
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
def get_by(id)
Article.find(params[id])
end
end
Thank you and sorry because of my bad english!

Your examples look pretty much what comes out of a scaffold, which is not too bad a start when learning how things can work (rails g scaffold article).
The relevant controller and views are then set up to do exactly what you are asking for: The controller holds a local variable (#article) ready for the view (ultimately _form.erb), whether or not the objects data is valid.
I wonder: What exactly happens? When you save with invalid data, the form should show up with the invalid data still in place. If you compare your form with the one that is created by the scaffold, you will notice that some output regarding validation errors is missing in your example. Try to add it, or start from scratch to see how it looks like.
When the data is valid and you still want the controller to show the user the form after hitting save, instead of redirect_to ... just render :edit.

Related

Edit action error (First argument in form cannot contain nil)

In this Rails app, Users can write Stories and add them to Collections. As they write a Story, users can add it to an existing Collection or create a new one while in the stories/new.html.erb view through a modal.
I have this working for the New action, but the Edit action is broken. It throws an error that says
First argument in form cannot contain nil or be empty on this line
<%= form_for [#user, #collection] do |f| %>
My code looks like this
stories_controller.rb
def new
#story = Story.new
authorize #story
#user = current_user
#collection = Collection.new
end
def edit
#story = Story.friendly.find(params[:id])
end
stories/edit.html.erb loading a _form.html.erb partial
<div class="modal-body">
<%= form_for [#user, #collection] do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control collection-desc-input-box", placeholder: "Give it a description (this is optional)" %>
</div>
<div class="form-group">
<%= f.submit class: "btn btn-lakeside" %>
</div>
<% end %>
</div>
routes.rb nested resource
resources :users do
resources :collections
EDIT:
Fixed the problem by putting Collection.new in the edit action. Would be good if someone can explain what's happening. I fixed this by trial and error. Thanks.
def edit
#story = Story.friendly.find(params[:id])
#user = current_user
#collection = Collection.new
end
initialize/set #user and #collection in your edit action, they are nil and so the error. Since they are initialised for new action, it is working.
You can do something like the following for #user and #collection can be initialised in their respective actions accordingly:
before_action :set_user, only: [:new, :edit]
private
def set_user
#user = current_user
end
You missed #user and #collection instance variable in store controller.
Try below code:
#stories_controller.rb
def new
#story = Story.new
authorize #story
#user = current_user
#collection = Collection.new
end
def edit
#story = Story.friendly.find(params[:id])
#user = User.find(params[:id])
#collection = Collection.find(params[:collection_id])
end

Rails form is not saving input to the database

I making a very simple RESTful app and when I input a string into the form field and submit it, the database hold NULL instead of the input string.
Here is my controller:
def create
#song = Song.create(params[:title])
flash[:success] = "You have successfully created a new project!"
redirect_to "/songs/#{#song.id}"
end
Here is my form in the new.html.erb file:
<%= form_for(#song) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<br>
<% end %>
If you are using rails < 4 then you should have
def create
#song = Song.create(params[:song])
flash[:success] = "You have successfully created a new project!"
redirect_to #song
end
and if you are using rails > 4 then you should have
def create
#song = Song.create(song_params)
flash[:success] = "You have successfully created a new project!"
redirect_to #song
end
private
def song_params
params.require(:song).permit(:title)
end

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

Redirect to show in another controller (Rails)

I have a form that allows the user to Post in the a group Show method. Upon posting, I want to redirect to the same page showing the new post. I'm using the following, but I get the error below. I'm not sure why #group is nil, because I've defined it in the show of my group controller.
No route matches {:id=>nil} missing required keys: [:id]
for
redirect_to group_path(#group)
<%=form_for([#post]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class = "field">
<%= f.label :event_name %>
<%= f.collection_select(:event_id, #events, :id, :title) %>
</div>
<div class = "field">
<%= f.text_area :comment, placeholder: "New Post..." %>
</div>
<%= f.hidden_field :user_id, value: current_user.id %>
<%=f.submit "Submit", class: "btn btn-large btn-primary" %>
<%end%>
class PostsController < ApplicationController
def create
if #post = Post.create(post_params)
flash[:success] = "Post Created!"
redirect_to group_path(#group)
else
redirect_to group_url
flash[:alert] = "Sorry - Post not created."
end
end
end
def show
#event = #group.events.build
#post = Post.new
#events = #group.events.includes(:posts)
#group = Group.find(params[:id])
end
In your create action you attempt to use the #group instance variable. You haven't defined it in the create action so you'll need to create it there if you want to use it. Since the call to create is in a separate request cycle the instance variables you defined in the show action are not available.
Update:
To get the group if you have an event_id and event belongs_to :group you would do:
event = Event.find(event_id)
#group = event.group
Set #group in create action. You have not assigned any value to #group there which is why you are getting error.
EDIT
As per your comment A Group has_many events so you can find the group as below:
#group = Event.find(params[:event_id]).group

undefined method update for nil class

After a user logs in, I'm trying to collect additional info to update in the data base
this is my controller
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.find params[:id]
end
def update
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
def create
#user = User.new(user_params)
if #user.save
#session[:user_id] = #user.id
#UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path(#user)
flash[:success] = "Welcome to InYourShoes!"
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def user_addinfo
params.require(:user).permit(:year)
end
end
the error occurs at the def update function if #user.update(user_addinfo), rails says its undefined.
def user_addinfo is a action method and def additional_info is the actual page
the view for the page:
<div class="row">
<div class="col-xs-12 col-sm-6 col-sm-offset-3">
<%= form_for(#user, :html => {:class => 'form-horizontal'}) do |f| %>
<fieldset>
<p>Do you have experience in Business? If yes, select one of the following:
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Select one <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Entrepreneurship</li>
<li>Investments</li>
<li>Management</li>
<li class="divider"></li>
<li>All of the Above</li>
</ul>
</div><!-- /btn-group -->
<%= f.text_field :year , :class => "form-control", :placeholder => "Years of experience" %>
</div>
</p>
<div class = "center form-actions">
<%= f.submit "Submit", class: "btn btn-lg btn-primary" %>
</div>
</fieldset>
<% end %>
</div>
</div>
am i saving the #user in the wrong place? I'm still new to the concept of #variablename instance variable... help and explanation is greatly appreciated
It is because you did't initialize the #user in "update" method.
Usually you need to do something like you did in "show" method.
#user = User.find(params[:id])
You current code, #user in "update" method is nil because you didn't assign any value to it. And a "nil" variable don't have the method "update".
You probably shouldn't try to overload your update function to capture the functionality of both edit and update (which you are doing, the other answers overlooked this). But the reason #user is nil upon form submission is probably because of this line:
render action: 'additional_info'
I'm guessing that line isn't doing what you expect. Rather than run the addition_info action and rendering the form, I believe that is simply performing the render. You probably want to redirect_to 'additional_info' and add a route for it if needed. Then you can ensure that the form is submitting the #user object correctly back to the update function.
You have to fetch the user additional information before updating it
def update
#user = User.find(params[:id])
if #user.update_attributes(user_addinfo)
#your redirection
else
#your redirection
end
end
def update
self.additional_info
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
#user doesn't exist with update, you'll need to create it first, which you've kind of done already

Resources