Rails controller action without a view - ruby-on-rails

I just want to do a rails action without a view.
In my 'routes.rb'
resources :pictures do
member do
post 'dislike'
end
end
In my 'PictureController.rb'
this does not work
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { render :action => :show, :id => params[:id], notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
neither do this
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { redirect_to #picture, notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
or even this (but this is not the case for me, i want a feedback to the user via json and via html)
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
render :nothing => true
end
But i keep getting this error message:
ActionView::MissingTemplate: Missing template pictures/dislike, application/like with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}.
How should i tell rails that this action in PicturesController does not needs a view?
Solved!
I didn't really solved the problem of telling rails i did not need a view, i just created another controller, put the method in it, and told rails routing to match the dislike action with a match call.
I cannot tell for sure, but i think it was a problem with the resources :picture in my routes.rb file...
But anyway, thank you guys!
=)

Something like this?
def dislike
#picture = Picture.find(params[:id]
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
render :nothing => true
end

Just created another controller with the dislike action:
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { redirect_to :back, notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
and modified my routes.rb to match this action:
match 'pictures/:id/dislike' => "likes#dislike", :via => :post
and my link to dislike now is
<%= link_to 'Dislike!', {:action => :dislike, :controller => :likes}, :method => :post %>

Most likely, the problem is that you're hitting this action via an ajax request. So the controller is looking for format.js, but you haven't specified a response for that format in your block. Thus it's falling through to the default.
Try
format.js { render json: #picture }
You may also need to tell the ajax request to expect a json response.

Related

Rails 3: Create and Delete action gives 'Template not found' error

I've come across a really strange error. I've installed 'Blogit' and am trying to add on a few bits and pieces. I'm encountering a strange error when I submit a new entry:
Template is missing
Missing template blogit/posts/create, blogit/application/create, application/create with
{:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: *
"/Users/James/Documents/Websites/Backpack Bug/app/views" * "/Users/James/.rvm/gems/ruby-
1.9.3-p0/gems/blogit-0.4.8/app/views" * "/Users/James/.rvm/gems/ruby-1.9.3-
p0/gems/kaminari-0.14.1/app/views" * "/Users/James/.rvm/gems/ruby-1.9.3-p0/gems/devise-
2.1.2/app/views"
I have a feeling this is to do with my routing. Here is routes.rb
appname::Application.routes.draw do
root :to => 'locations#index'
devise_for :users
resources :locations do
collection do
get 'location'
end
end
mount Blogit::Engine => "/blog", :as => "blog"
end
Here is the posts controller:
module Blogit
class PostsController < ApplicationController
unless blogit_conf.include_admin_actions
before_filter :raise_404, except: [:index, :show, :tagged]
end
blogit_authenticate(except: [:index, :show, :tagged])
blogit_cacher(:index, :show, :tagged)
blogit_sweeper(:create, :update, :destroy)
def index
respond_to do |format|
format.xml {
#posts = Post.order('created_at DESC')
}
format.html {
#posts = Post.for_index(params[:page])
}
format.rss {
#posts = Post.order('created_at DESC')
}
end
end
def show
#post = Post.find(params[:id])
#comment = #post.comments.new
end
def tagged
#posts = Post.for_index(params[:page]).tagged_with(params[:tag])
render :index
end
def location
#georesult = Geocoder.search(params[:location])
respond_to do |format|
format.html {render :layout=>false}# venues.html.erb
end
end
def new
#post = current_blogger.blog_posts.new(params[:post])
#location = #post.locations.build
end
def edit
#post = current_blogger.blog_posts.find(params[:id])
#location = #post.locations.new
end
def create
#post = current_blogger.blog_posts.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, :method => :get, notice: 'Blog post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
#post = current_blogger.blog_posts.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to #post, notice: 'Blog post was successfully updated.'
else
render action: "edit"
end
end
def destroy
#post = current_blogger.blog_posts.find(params[:id])
#post.destroy
redirect_to posts_url, notice: "Blog post was successfully destroyed."
end
private
def raise_404
# Don't include admin actions if include_admin_actions is false
render file: "#{Rails.root}/public/404.html", status: :not_found, layout: false
end
end
end
All I've changed from the source so far is, I've basically created a multipart form which allows searches for locations and submits them to a locations table in the same post action. Not sure if this has anything to do with it. I can post up all this code but it's pretty lengthy. Let me know if you think this would be useful too.
Thanks a lot for all your help! Frankly, I'm stumped.
James
Just a hunch: see if your location action is getting called. I just experienced a slightly different error where any calls to redirect_to in my controller were causing my location method in the same controller to get called. (Putting a raise at the beginning of the location method will quickly let you know.)
I haven't tried investigation exactly why this was happening, but renaming my location action fixed this (obviously, this required changing any other code that referenced that endpoint, like AJAX requests in my JavaScript). Rails magic, no doubt.

returning rails object by id & routing problem?(Ruby rails)

This should have been a relatively simple one but I must be making a mistake with my routes or something. I want to return an active record as json based on an id. So heres what I have and in my eyes it should have worked.
The route:
match '/repository/infoid/(.:id)(.:format)' =>'repo#infoID', :via =>:get
The def within the controller
def infoID
puts (params[:id])
#specificObject = myObject.find_by_id(params[:id])
respond_to do |format|
format.xml{
render :xml =>
{
:returnedObject => #specificObject
}
}
end
end
Why is it that when I go to my address of http://127.0.0.1:3008/repository/infoid/1.xml
I get no route found for /infoid/1.xml
get '/repository/infoid/:id' => 'repo#infoID'
little refacrtoring for controller
def infoID
#specificObject = MyObject.find(params[:id])
respond_to do |format|
format.html{}
format.xml{
render :xml => #specificObject
}
end
end

Rails 3 app doesn't redirect after AJAX form submission

I have an Authlogic login form with :remote => true that does a little inline validation with an RJS template if the user/password isn't valid. This works fine, but when the credentials are valid, it doesn't properly redirect elsewhere.
Here's the controller that responds to the form input:
class UserSessionsController < ApplicationController
respond_to :html, :js
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
flash[:notice] = "Login successful!"
format.html { redirect_to account_url }
else
format.js
end
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
redirect_to root_path
end
end
The format.js part works but if the user/password are good (format.html), nothing happens. However, if I look a development.log, it is requesting the account_url page. It's just not redirecting you in the browser. I think it's returning the account page via AJAX and I really just want a normal redirect.
The HTML for the form is this:
<%= simple_form_for(
:user_session, #user_session,
:url => { :controller => 'user_sessions', :action => "create" },
:html => { :id => 'login-dropdown' }, :remote => true) do |f| %>
I found a way to fix it. Per http://www.ruby-forum.com/topic/168406#945053, I added the following to my application controller:
def redirect_to(options = {}, response_status = {})
if request.xhr?
render(:update) {|page| page.redirect_to(options)}
else
super(options, response_status)
end
end
This prevents the redirect response from being delivered via xhr. If there's a more "correct" way of doing this in the controller, I'd like to hear it, though.
You can do like below :
in allpication.js
$(document).ready(function(){
$(document).ajaxError( function(e, xhr, options){
if("401" == xhr.responseText)
{
$(location).attr('href','/users/sign_in');
}
});
})
and controller's method has below code:
respond_to do |format|
format.html {redirect_to #new_user_session_url}
format.js { render :text=>'401' ,:status=>401}
end
But I think there is better way to do so....
app
views
user_sessions
create.js.erb(create file this)
in your create action add this code
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
flash[:notice] = "Login successful!"
#url = account_url
end
format.js
end
end
in your "create.js.erb"
window.location.replace(<%= #url %>);

Reverse order of display of blog entries and comments, Ruby on Rails

I am new to rails so could use some help here. I have followed several tutorials to create a blog with comments and even some of the AJAX bells and whistles and I am stuck on something that I hope is easy. The default display for both blogs and comments is to list the oldest first. How do I reverse that to show the most recent entries and the most recent comments at the top. Don't really know if this is a function of the controller or model. I have done some customization so here is the code for the controller .rb files if it helps.
COMMENTS CONTROLLER
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
POSTS CONTROLLER
class PostsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /posts
# GET /posts.xml
def index
#posts = Post.all(:include => :comments)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
# GET /posts/new
# GET /posts/new.xml
def new
#post = Post.new
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(#post) }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
private
def authenticate
authenticate_or_request_with_http_basic do |name, password|
name == "admin" && password == "secret"
end
end
end
As jtbandes pointed out, to reverse the posts in the index, you'd change the line in your index action to read:
#posts = Post.all(:include => :comments, :order => "created_at DESC")
In order to reverse the listing of your comments, there are two possibilities.
Option 1: In your post model you can declare your relationship like so:
class Post < ActiveRecord::Base
has_many :comments, :order => "created_at DESC"
end
Option 2: In your index view, simply reverse the array of each post's comments before displaying them:
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
The options have different use cases. In option 1, you're saying that throughout your entire application, any time you refer to the comments on a post, those comments should be retrieved from the database in the specified order. You're sort of saying that this is an intrinsic property of comments in your application - posts have many comments, which are by default ordered newest first.
In option 2, you're simply reversing the comments in the index page before they're rendered. They were still retrieved in the original order (oldest first) from the database, and they'll still appear in that order anywhere else you access the comments of a post in your application.
If you're looking for a more generic way to reverse the order of the .each method, Rails has the .reverse_each method. Like so:
<% #posts.reverse_each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
#posts = Post.find(:all, :include => :comments, :order => "published_at DESC")
It looks like you can reverse the order using find: something like Post.find(:all, :order => "created_at DESC"). The same should apply to comments.
.reverse_each method bumping with will_paginate
here is the solution
#posts = Post.all.paginate(:order => "created_at DESC",:page => params[:page],:per_page => 5)
try use: reverse_order
Client.where("orders_count > 10").order(:name).reverse_order
this will execute the SQL:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC
If no ordering clause is specified in the query, the reverse_order orders by the primary key in reverse order.
Client.where("orders_count > 10").reverse_order
which will execute:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
http://edgeguides.rubyonrails.org/active_record_querying.html#reorder

Routing to new action (Rails)

I have an action in my PostsController named 'tagged', which I want to return all posts tagged with whatever term.
In my routes.rb I have the following (at the top):
map.connect 'posts/tagged/:tag', { :controller => 'posts', :action => 'tagged', :tag => /[a-z\-]+/ }
Yet navigating to posts/tagged/yes returns a RecordNotFound error:
Couldn't find Post without an ID
In my tagged.html.erb file, I'll eventually be using the find_tagged_with method from acts_as_taggable_on_steroids, but for now I've put a simple Post.find(:all) to eliminate the possibility of error.
It seems like my map.connect is being overridden, and the same error occurs even if I comment the whole of the routes.rb file out except my new line.
Ok, because you can comment out the default routes that means your problem is not in your routes at all. It's that your tagged action in the posts controller probably has something like this.
def tagged
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Or perhaps if you spent a little more time it looks like this:
def tagged
#post = Post.find(params[:tagged])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Where as what you want is this:
def tagged
#post = Post.find(:all, :conditions => {:tagged => params[:tagged]})
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Anyway, you should be writing functional tests for this stuff and not testing in the browser.
Why not add a RESTful route for the "tagged" action?
map.resources :posts, :member => { :tagged => :put }

Resources