I have two models: page and authors, when i choose the destroy method it just returns the show page. The models are linked by telling the model that the author has_many :pages and the page belongs to many :author.
this is the code for my page controller:
class PagesController < ApplicationController
def index
#pages = Page.find(:all, :order => 'created_at DESC')
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
end
def edit
#page = Page.find(params[:id])
end
def create
#page = Page.new(params[:page])
if #page.save
redirect_to(#page, :notice => 'Page was successfully created.')
else
render :action => "new"
end
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(params[:page])
redirect_to(#page, :notice => 'Page was successfully updated.')
else
render :action => "edit"
end
end
def destroy
#page = Page.find(params[:id])
#page.destroy
end
def author
#pages = #author.pages
end
end
Where should I be looking to solve this problem, when i hit destroy it semds me to the page to destroy but nothing more, no :notice appears it just seems to not have the destroy method.
Thank you
I don't know what you mean by
choose the destroy method
But I'm assuming you're just accessing the pages/:id url in your browser? This is the show action as you said.
In order to actually destroy your model (ie. access the destroy action in the controller) you need to send a DELETE to /pages/:id.
This is usually accomplished using something like:
<%= link_to 'Destroy', #page, :confirm => 'Are you sure?', :method => :delete %>
Note the :method => :delete. This will actually send a DELETE to the controller (assuming you've got your rails.js included to take care of this) and thus map to the destroy action instead of the show action
Have you disabled JavaScript in your browser? :)
A couple of things to look at:
It's not clear what type of HTTP request you are sending to your application. The fact that the show action seems to be triggered makes me think that your request is an HTTP GET method. If you want the destroy action to be invoked, make sure it is an HTTP DELETE method.
Have you checked your database to see if the ActiveRecord had been destroyed? It could be that you are not seeing any notice simply because you are not setting a flash notice message. For example:
def destroy
#page = Page.find(params[:id])
flash[:notice] = "Page successfully removed"
#page.destroy
# You may also want to have a redirect here, e.g. redirect_to #pages
end
On a separate note, not sure what you are trying to achieve with the author method in your controller but it doesn't look right. It's not restful and it seems to return an array of pages rather than an author.
Related
When I try to delete #article, I am getting this error: ActiveRecord::RecordNotFound in ArticlesController#destroy, Couldn't find Article with id=1... But when I go back on Index page, #article is deleted.
What should I do?
Destroy method:
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to 'root'
end
Link for delete(/show.html.erb):
<%= link_to "delete", article_path(#article), method: :delete %>
If you need more files, I will upload them..
Try using:
redirect_to :root if #article.destroy
If you want to avoid errors when hitting the destroy action for a record that is already deleted you could use the following:
def destroy
if article = Article.find_by(id: params[:id])
article.destroy
end
redirect_to root_path
end
find_by returns nil if it doesn't find the record while find throws an exception. nil is considered 'falsey' by ruby which will bypass the body of the if when the record is not found.
It is also best to use a path helper to avoid having 'magic' strings in your code that you have to remember to update if you decide to change your routes file.
Simply Just change a little in the redirect_to line
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to :action => :index #this will redirect to article index page if delete action was successful
end
Like #bhanua1 say
try using redirect to :root if #article.destroy
In ruby on rails project, when I create a reporter successfully, page is redirect to another action from another controller; and when the page is redirect, the page is reloaded. In this project, I have 2 controller:
reporters_controller.rb:
class ReportersController < ApplicationController
layout "reporter"
def new
#reporter = Reporter.new
#gomrokaddresses = Gomrokaddress.find(:all)
end
def create
#reporter = Reporter.new(reporter_params)
if #reporter.save
#redirect_to new_reporter_path
redirect_to new_problem_path(:id => #reporter.id)
else
#existreporter = Reporter.find_by(params[:rep_user_name])
redirect_to new_problem_path(:id => #existreporter.id)
end
end
problems_controller.rb
def new
#reporter = Reporter.find(params[:id])
#problem = #reporter.problems.build
end
def create
#reporter = Reporter.find(params[:id])
#problem = #reporter.problems.build(problem_params)
if #problem.save
redirect_to new_problem_path(:id => #reporter.id)
else
redirect_to new_problem_path(:id => #reporter.id)
end
end
reporter.rb
class Reporter < ActiveRecord::Base
has_many :problems
end
problem.rb
class Problem < ActiveRecord::Base
belongs_to :reporter
end
I create reporter and problem with form_for in view. When I complete form_for in new.html.erb (for reporter) and submit, create action (that exist in reporter_controller) is called, and then if information are true, page is redirect to /problems/new. Because of this redirect_to, the page is reload; I don't want reload the page, just when I create the reporter, the form_for of reporter replace with the form_for of problem. How can I do this?
Try this in your controller
redirect_to new_problem_path(:id => #reporter.id), format: 'js'
Hope this helps!
A controller action renders the corresponding view template by default. Here, the action "problems#new" automatically renders "views/problems/new.html.erb".
In your code, you've redirected to the URL represented by new_problem_path, and a GET request to that URL is routed to the "problems#new" action. Thus, the action is invoked and its template is loaded.
However, there are ways to override this default behavior if you want to call the action without loading the view template.
Also, redirect_to is different from AJAX. For AJAX, you'd use something like
def create
...
respond_to do |format|
if #reporter.save
format.html { redirect_to ... }
format.js
else
format.html { render action: ... }
format.js
end
end
end
and then add the option :remote => true to form_for in the form that you use to create the new reporter.
But I'm not sure if this would accomplish what you're trying to do. Could you please explain your question further?
The functionality I'm trying to build allows Users to Visit a Restaurant.
I have Users, Locations, and Restaurants models.
Locations have many Restaurants.
I've created a Visits model with user_id and restaurant_id attributes, and a visits_controller with create and destroy methods.
Thing is, I can't create an actual Visit record. Any thoughts on how I can accomplish this? Or am I going about it the wrong way.
Routing Error
No route matches {:controller=>"restaurants", :location_id=>nil}
Code:
Routes:
location_restaurant_visits POST /locations/:location_id/restaurants/:restaurant_id/visits(.:format) visits#create
location_restaurant_visit DELETE /locations/:location_id/restaurants/:restaurant_id/visits/:id(.:format) visits#destroy
Model:
class Visit < ActiveRecord::Base
attr_accessible :restaurant_id, :user_id
belongs_to :user
belongs_to :restaurant
end
View:
<% #restaurants.each do |restaurant| %>
<%= link_to 'Visit', location_restaurant_visits_path(current_user.id, restaurant.id), method: :create %>
<% #visit = Visit.find_by_user_id_and_restaurant_id(current_user.id, restaurant.id) %>
<%= #visit != nil ? "true" : "false" %>
<% end %>
Controller:
class VisitsController < ApplicationController
before_filter :find_restaurant
before_filter :find_user
def create
#visit = Visit.create(params[:user_id => #user.id, :restaurant_id => #restaurant.id])
respond_to do |format|
if #visit.save
format.html { redirect_to location_restaurants_path(#location), notice: 'Visit created.' }
format.json { render json: #visit, status: :created, location: #visit }
else
format.html { render action: "new" }
format.json { render json: #visit.errors, status: :unprocessable_entity }
end
end
end
def destroy
#visit = Visit.find(params[:user_id => #user.id, :restaurant_id => #restaurant.id])
#restaurant.destroy
respond_to do |format|
format.html { redirect_to location_restaurants_path(#restaurant.location_id), notice: 'Unvisited.' }
format.json { head :no_content }
end
end
private
def find_restaurant
#restaurant = Restaurant.find(params[:restaurant_id])
end
def find_user
#user = current_user
end
end
I see a lot of problems here. The first is this line of code in your VisitController's create action (and identical line in your destroy action):
#visit = Visit.create(params[:user_id => #user.id, :restaurant_id => #restaurant.id])
params is a hash, so you should be passing it a key (if anything), not a bunch of key => value bindings. What you probably meant was:
#visit = Visit.create(:user_id => #user.id, :restaurant_id => #restaurant.id)
Note that you initialize #user and #restaurant in before filter methods, so you don't need to access params here.
This line of code is still a bit strange, though, because you are creating a record and then a few lines later you are saving it (if #visit.save). This is redundant: Visit.create initiates and saves the record, so saving it afterwards is pretty much meaningless. What you probably want to do is first initiate a new Visit with Visit.new, then save that:
def create
#visit = Visit.new(:user_id => #user.id, :restaurant_id => #restaurant.id)
respond_to do |format|
if #visit.save
...
The next thing I notice is that you have not initiated a #location in your create action, but you then reference it here:
format.html { redirect_to location_restaurants_path(#location), notice: 'Visit created.' }
Since you will need the location for every restaurant route (since restaurant is a nested resource), you might as well create a method and before_filter for it, like you have with find_restaurant:
before_filter :find_location
...
def find_location
#location = Location.find(params[:location_id])
end
The next problem is that in your view your location_restaurant_path is passed the id of current_user and of restaurant. There are two problems here. First of all the first argument should be a location, not a user (matching the order in location_restaurant_path). The next problem is that for the _path methods, you have to pass the actual object, not the object's id. Finally, you have method: :create, but the method here is referring to the HTTP method, so what you want is method: :post:
link_to 'Visit', location_restaurant_visits_path(#location, restaurant.id), method: :post
You'll have to add a find_location before filter to your RestaurantController to make #location available in the view here.
There may be other problems, but these are some things to start with.
location_id is nil and the path definition doesn't say (/:location_id) forcing a non-nil value there in order to route to that path; create a new route without location_id if you can derive it from a child's attribute (i.e. a restaurant_id refers to a Restaurant which already knows its own location_id).
Since, I am new to rails, so I have want to know a small functionality.
I have a reports model in my rails 3 application(not by scaffolding). I am displaying reports one by one through ajax functionality. I want to add a delete link to my each report. I have also created the destroy method in my controller. Now, I don't know how to delete a specific report when I click on the delete link of that particular report.
Here's my controller code:-
class ReportsController < ApplicationController
def index
#reports = Report.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#report = Report.create(:description => params[:description])
respond_to do |format|
if #report.save
format.html { redirect_to reports_path }
format.js
else
flash[:notice] = "Report failed to save."
format.html { redirect_to reports_path }
end
end
end
def destroy
#report = Report.find(params[:id])
if #report.destroy
format.html { redirect_to reports_path }
format.js
end
end
end
You can assume that my reports are being displayed in the twitter-timeline format and I want to add the delete report feature to each report. Please help me out.
In your view you'd add a link, button, etc. to send the delete action back to the server.
Using link_to for example:
link_to("Destroy", report_path(report), :method => :delete, :confirm => "Are you sure?")
You can do the same with button_to.
Update:
Sorry I missed the AJAX mention (thanks Jeffrey W.).
You'll also want to add :remote => true if you want to send the delete via AJAX.
I have been trying to get to grips with jQuery and been following a railscast on adding an Ajax add review form, which works fine but I would now like to add into it the ability for a review to belong to a user as well as a venue.
Reviews controller
def create
#review = Review.create!(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end
views\reviews\create.js.erb
$("#new_review").before('<div id="flash_notice"><%= escape_javascript(flash.delete(:notice)) %></div>');
$("#reviews_count").html("<%= pluralize(#review.venue.reviews.count, 'Review') %>");
$("#reviews").append("<%= escape_javascript(render(:partial => #review)) %>");
$("#new_review")[0].reset();
I have tried changing the controller to:
def create
#review = #current_user.reviews.create!(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end
but it just wont submit, with no errors.
I think I have the models set correctly with belongs_to and has_many, I think this is a controller issue I'll add other code bits if needed.
Development log
NoMethodError (undefined method `reviews' for nil:NilClass):
app/controllers/reviews_controller.rb:14:in `create'
Thanks for any help!
It appears that your error is residing with #current_user. According to your development log, #current_user is nil when you call #current_user.reviews on it. I would say track down where this #current_user instance variable is being set and find out why it is nil. Now, what kind of authentication are you using? Most authentication plugins, especially those used by Ryan Bates of the Railscasts you mentioned, use a local variable, say just current_user, as the means to access the currently signed in user. I know I do in all my code.
So, rewrite the line as
#review = current_user.reviews.create!(params[:review])
and see if that works. If it doesn't, change it back and then track down where this #current_user is being set. Chances are good it is being set in a before_filter :method_name at the beginning of your controller.
Calling create! (with exclamation mark) will throw an exception and thus abort your create action if saving fails. Check your log/development.log for these exceptions.
Use build instead of create and lose the exclamation mark.
def create
#review = #current_user.reviews.build(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end