I am building a rails app to learn about nested controllers actions. Hence I have Projects to which Tickets are nested underneath. It's basically a rip-off from Rails Action. Now, I am trying to add edit action in Ticket's controller.
Everything works fine in Projects, ie, all the actions.
Everything seems to work fine in Tickets. As stated earlier, it's a rip-off from Rails Action. So trying learn how to put in correct stuff within blank actions, ie, Edit, Show, Update, and Destroy
When I added edit action in Tickets show page, and clicked on it, it showed the page, but the form fields are blank.
The url path is correct: http://127.0.0.1:3000/projects/2/tickets/2/edit so that means the resources are set up correctly.
How do I fix this so it shows the previous content? My vague understanding is that it may have to do with the form?
Current Tickets Controller
class TicketsController < ApplicationController
#which actions are necessary? learn how to not need set_project set_ticket
before_action :set_project
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
def create
#ticket = #project.tickets.build(ticket_params)
if #ticket.save
flash[:notice] = "Ticket has been created."
redirect_to project_path(#project)
else
flash.now[:alert] = "Ticket has not been created."
render "new"
end
end
def new
#ticket = #project.tickets.build
end
def show
end
def edit
#ticket = #project.tickets.find(params[:id])
end
def update
end
def destroy
end
private
def ticket_params
params.require(:ticket).permit(:title, :description)
end
def set_project
#project = Project.find(params[:project_id])
end
def set_ticket
#ticket = #project.tickets.find(params[:id])
end
end
show.html.erb - Ticket
<h1><%= #project.title %></h1>
<h3><%= #ticket.title %></h3>
<%= link_to "All Projects", projects_path %>
<%= link_to "Edit Ticket", edit_project_ticket_path %>
_form.html.erb - Ticket
<%= form_for([#project, #project.tickets.build]) do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
EDIT, I've updated the _form.html.erb to the following code beneath, and it seems to work, ie, it shows the contents to modify. Yay. But when I click on Update Ticket button, it doesn't move beyond the page.
<%= form_for [#project,#ticket] do |f| %>
EDIT AGAIN
I updated the ticket's controller actions for Show and Update, and now it seems to work! Including it for feedback in case this was done incorrectly.
class TicketsController < ApplicationController
#which actions are necessary? learn how to not need set_project set_ticket
before_action :set_project
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
def create
#ticket = #project.tickets.build(ticket_params)
if #ticket.save
flash[:notice] = "Ticket has been created."
redirect_to project_path(#project)
else
flash.now[:alert] = "Ticket has not been created."
render "new"
end
end
def new
#ticket = #project.tickets.build
end
def show
#ticket = #project.tickets.find(params[:id])
end
def edit
#ticket = #project.tickets.find(params[:id])
end
def update
if #ticket.update(ticket_params)
flash[:notice] = "Ticket has been updated."
redirect_to [#project, #ticket]
else
flash.now[:alert] = "Ticket has not been updated."
render "edit"
end
end
def destroy
end
private
def ticket_params
params.require(:ticket).permit(:title, :description)
end
def set_project
#project = Project.find(params[:project_id])
end
def set_ticket
#ticket = #project.tickets.find(params[:id])
end
end
Related
I have created a simple_form_For common for both new and update,
currently, it's working fine for new but for edit/update, it calling the wrong URL.
class NewsfeedsController < ApplicationController
before_action :find_post, only: [:show, :destroy, :edit, :update]
def index
#posts = Post.all.order("created_at DESC")
end
def show
# before_action is taking care of all 4 i.e(sho,edit,update and destroy)..Keeping it DRY
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to newsfeed_path(#post)
else
render 'edit'
end
end
def destroy
end
private
def post_params
params.require(:post).permit(:content)
end
def find_post
#post = Post.find(params[:id])
end
end
In Form.html
<%= simple_form_for #post, url: newsfeeds_path(#post) do |f| %>
<%= f.input :content,label: false, placeholder: "write your post here..." %>
<%= f.button :submit %>
<% end %>
on inspect element on browser,
i am getting action wrong,
it needs to be action="/newsfeeds/7"
Please guide
As you are using common _form for new and update, you need to add condition in url respectively,
<%= simple_form_for #post, url:(#post.new_record? ? newsfeeds_path : newsfeed_path(#post)) do |f| %>
This will help you using both new and update method.
Hope this will help.
Update action should be newsfeed_path(#post) and not newsfeeds_path(#post). Please correct it and try again!
<%= simple_form_for #post, url: newsfeed_path(#post) do |f| %>
Hope that helps!
I am building an app for practice,(Instagram replica), and I am having a really hard time getting a feature to work.
What I want to happen is, a user is able to edit or delete their own comments about a picture. I was able to get the delete feature to work, but I am unable to figure out the 'Edit comment' feature. I want the user to be able to edit the comment from within the picture show page. Code is below.
pics_controller.rb
class PicsController < ApplicationController
before_action :find_pic, only: [:show, :edit, :update, :destroy, :upvote]
before_action :authenticate_user!, except: [:index, :show]
before_action :require_same_user, only: [:edit, :update, :destroy]
def index
#pics = Pic.all.order("created_at DESC")
end
def show
end
def new
#pic = current_user.pics.build
end
def create
#pic = current_user.pics.build(pic_params)
if #pic.save
redirect_to #pic, notice: "Your pic has been posted!"
else
render :new
end
end
def edit
end
def update
if #pic.update(pic_params)
redirect_to #pic, notice: "Awesome! Your Pic was updated!"
else
render :edit
end
end
def destroy
if #pic.destroy
redirect_to root_path
end
end
def upvote
#pic.upvote_by current_user
redirect_back fallback_location: root_path
end
private
def pic_params
params.require(:pic).permit(:title, :description, :image)
end
def find_pic
#pic = Pic.find(params[:id])
end
def require_same_user
if current_user != #pic.user
flash[:danger] = "You can only edit or delete your own pictures"
redirect_to root_path
end
end
end
comments_controller.rb
class CommentsController < ApplicationController
def create
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.create(params[:comment].permit(:name, :body))
redirect_to pic_path(#pic)
end
def edit
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.find(params[:id])
redirect_to #pic
end
def update
#comment = #pic.comments.find(params[:id])
#comment.update_attributes(comment_params)
if #comment.save
redirect_to #pic
end
end
def destroy
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.find(params[:id])
#comment.destroy
redirect_to pic_path(#pic)
end
def show
#pic = Pic.find(params[:pic_id])
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
And here is the (_comment.html.erb) partial being called from the show page
<div class="card" style="width: 18rem;">
<div class="card-header">
<span class="badge badge-dark"><%= comment.name %></span>
</div>
<ul class="list-group list-group-flush">
<p><%= comment.body %></p>
</ul>
</div>
<% if user_signed_in? && comment[:body].present? %>
<p><%= link_to 'Delete Comment', [comment.pic, comment], method: :delete, class: "btn btn-danger",
data: { confirm: "Are you sure?" } %></p>
<p><%= link_to 'Edit Comment', edit_pic_comment_url(#pic, comment), class: 'btn btn-primary' %></p>
<% end %>
Any help is greatly appreciated. TIA
You need to ajaxify for that scenario. The steps will be:
Create the edit link with data-remote=true option. It'll enable the link to hit on the server with a ajax request. Also, add a editable div.
Edit
<div id="comment_#{comment.id}_form"></div>
In the edit method respond the request using js. Like:
def edit
respond_to do |format|
format.js # actually means: if the client ask for js -> return edit.js
end
end
Create edit.js file. In there, render the comment _form.html.erb on the defined div with ID - comment_4_form (Lets assume you're now editing comment with id 4).
It's not elaborated I know. The solution will be much bigger if I elaborate. But you are good to go if you understand the cycle.
I am building my first RoR application and it involves Assignments with Tasks. The user has the ability to Create Assignments, add Tasks to those assignments, and also mark assignments complete. I have an "Accomplishments" page that show cases a featured User with "most completed" assignments (User that has more than 5 assignments completed). Where my problem lies is that the User doesn't change as the assignments completed count does. Currently I only have 2 users. User1 has completed 8 assignments, User2 has completed 7 assignments. User2 is being displayed as the "Featured User with most completed assignments".
My code is as follows:
Assignments Controller
class AssignmentsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_assignment, only: [:show, :edit, :update,
:destroy]
#GET/ASSIGNMENTS
def index
user = User.find params[:user_id]
#incomplete_assignments = user.assignments.incomplete
#complete_assignments = user.assignments.complete
end#index
def new
#assignment = current_user.assignments.build
#assignment.tasks.build
end#new
#POST
def create
#assignment = current_user.assignments.build(assignment_params)
if #assignment.save
redirect_to [current_user, #assignment], notice: "Assignment was created successfully!"
else
render :new
end
end #create
def show
##user = current_user.assignments
#task = Task.new
end#show
#PATCH
def edit
end
def update
#assignment.update(assignment_params)
redirect_to [current_user, #assignment], notice: "Assignment updated successfully!"
end#update
#DELETE
def destroy
#assignment.destroy
redirect_to [current_user, #assignment], notice: "Assignment was deleted successfully!"
end #destroy
def completed
Assignment.where(id: params[:assignment_ids]).update_all(status: true)
redirect_to user_assignments_path(current_user.id)
end#completed
private
#STRONG PARAMS
def set_assignment
#assignment = Assignment.find(params[:id])
end
def assignment_params
params.require(:assignment).permit(:name, :due_date, task_attributes: [:name])
end
end#class
Users Controller
class UsersController < ApplicationController
before_action :authenticate_user!
def show
#user = User.find(params[:id])
#assignment = Assignment.new
redirect_to user_path(#user)
end
def show_completed
#users = User.all
end
end
My view with Accomplishments
<h3> Status of who has done what</h3>
<br>
<% for user in #users %>
<%= user.email %> has completed <%= user.assignments.count %> assignments. <br>
<% end %>
<% if user.assignments.complete.count > 5 %>
<h1> **Featured User** </h1>
<h2><%= user.email %> has completed the most assignments!</h2>
<% else %>
<p> Not enough completed Assignments to be featured!</p>
<% end %>
<%= link_to 'Back to your asssignments', user_assignments_path(current_user, #assignment) %>
This may be a matter of a misunderstanding on how to properly use .count in a method, or something as simple as that in my View where I say display the user with assignments greater than 5 my application is doing just that.
I have an existing Rails application where users can create classifieds/ads for boats. Currently there is no payment integrated and once user submits the form, it gets posted. Now I am looking to add Spripe Checkout (as it seems the easiest, correct me if i'm wrong) to my app. I am not sure what would be the best way to approach this. Ideally I would like the user to submit the form and then be asked to pay.
Also, I am not sure which approach I should take: 1) the ad gets created in the database first and then with the payment a Boolean column value (for example "payment") gets changed or 2) the ad's database record gets created only with a successful payment.
Should I create a new Charges controller like Stripe tutorial suggests or incorporate it in my existing AdsController?
ads_controller.rb
class AdsController < ApplicationController
before_action :logged_in_user, only: [:edit, :update, :new]
before_action :correct_user, only: [:edit, :update, :destroy]
def index
if params[:category].blank? && params[:state].blank?
#ads = Ad.all.order("created_at DESC")
elsif params[:category].blank?
#state_id = State.find_by(name: params[:state]).id
#ads = Ad.where(state_id: #state_id).order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#ads = Ad.where(category_id: #category_id).order("created_at DESC")
end
#ads = #ads.paginate(page: params[:page], :per_page => 21)
end
def new
#ad = Ad.new
end
def create
#ad = current_user.ads.build(ad_params)
if #ad.save
flash[:success] = "Ad successfully created"
redirect_to #ad
else
render 'new'
end
end
def show
#ad = Ad.find(params[:id])
end
def edit
#ad = Ad.find(params[:id])
end
def update
#ad = Ad.find(params[:id])
if #ad.update_attributes(ad_params)
flash[:success] = "Ad successfully updated"
redirect_to #ad
else
render 'edit'
end
end
def destroy
#ad.destroy
flash[:success] = "Ad deleted"
redirect_to request.referrer || root_url
end
private
def ad_params
params.require(:ad).permit(:title, :price, :year, :location, :description, :contact_name, :contact_number, :category_id, :picture, :picture2, :picture3, :state_id)
end
def correct_user
#ad = current_user.ads.find_by(id: params[:id])
redirect_to root_url if #ad.nil?
end
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in"
redirect_to login_path
end
end
my current form:
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#ad, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label "Category:" %>
<%= f.collection_select :category_id, Category.all, :id, :name, { prompt: "Select Category" }, class: 'form-control' %>
# Lots of other form fields
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
Any thoughts on this will be highly appreciated.
It would be more railsesque to create a separate controller than build it into the ads controller. You should definitely wrap the entire db process in what is known as a 'transaction' and look to save the add only on successful payment. If any part fails throughout the 'transaction' process it will roll back your database and maintain conformity.
The jstripe tutorials are very in depth but if you're looking for more information and specific examples I read a great book I bought on this subject that walked me around a lot of the pitfalls and gotchas you may run into:
https://www.masteringmodernpayments.com/
EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end