What's the difference between respond_to and respond_with in Rails? - ruby-on-rails

When I'm sending data to my controller I'm getting the following error
with the parameters
{"title"=>"some",
"user_id"=>"2",
"task"=>{"title"=>"some"}}
Why is that so? And what's the difference between respond_to and respond_with in Rails?
class TasksController < ApplicationController
respond_to :json
def create
respond_with current_user.tasks.create(task_params)
end
private
def task_params
params.require(:task).permit(:id, :title, :due_date, :priority, :complete)
end
end
When I'm using respond_to it says Undefined method upcase for Task

It's saying it doesn't recognize the format of your response. Since respond_with current_user.tasks.create(task_params) will generate a html response.
In your routes.rb change
resources :tasks
to
resources :tasks, :defaults => {:format => "json"}
This question may help you

Try this one:
def create
respond_with(current_user.tasks.create(task_params), :location => tasks_url)
end

Related

no implicit conversion of nil into String Ruby on Rails

can somebody help with this, please?
My blog post share isn't showing an image on Twitter. I benchmarked other websites and noticed all the blog post working websites had a domain URL in the prior to the image URL. So, I added on it and blog post started working!!!. Yayy
Then, I've encountered another problem. When I click to see a blog page, it shows an error message(per below)
ActionView::Template::Error (no implicit conversion of nil into String):
21: %meta{:content => "https://www.joynus.com"+#post.preview_image.try(:data).try(:url), :name => "twitter:image"}
My post controller
class PostsController < ApplicationController
before_filter :authorize, only: [:edit, :update, :new, :create, :destroy]
before_filter :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.order("created_at DESC").page(params[:page]).per(9)
respond_to do |format|
format.html
format.rss { render :layout =>false }
end
end
def show
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_url
else
render 'new'
end
end
def edit
end
def update
if #post.update_attributes(post_params)
redirect_to post_url(#post), notice: "#{#post.title} Updated"
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to posts_url, notice: "#{#post.title} Deleted"
end
private
def post_params
params.require(:post).permit(:title, :social_title, :contents, :author_id, :approved, :summary, :preview_image_id, :category)
end
def find_post
#post = Post.friendly.find(params[:id])
# If an old id or a numeric id was used to find the record, then
# the request path will not match the post_path, and we should do
# a 301 redirect that uses the current friendly id.
if params[:action] == 'show' && request.path != post_path(#post)
return redirect_to #post, :status => :moved_permanently
end
end
end
And, my post.rb
class Post < ActiveRecord::Base
extend FriendlyId
friendly_id :slug_candidates, use: [:slugged, :history]
belongs_to :preview_image, class_name: 'Ckeditor::Picture'
belongs_to :author, class_name: 'User'
## Validations
validates :contents, presence: true
validates :title, presence: true
validates :social_title, presence: true
validates :summary, presence: true, length: 1..300
validates :author, presence: false
validates :category, presence: true
delegate :full_name, to: :author, prefix: true, allow_nil: false
## Instance Methods
def slug_candidates
[
:slug_title,
[:id, :slug_title]
]
end
def slug_title
title&.downcase
end
def should_generate_new_friendly_id?
title_changed?
end
def raw_post
self.contents.html_safe
end
def preview_image_thumb(dimensions = '100x')
preview_image.try(:data).try(:thumb, dimensions).try(:url)
end
def self.preview_image_dimensions
'350x'
end
end
Is there a way to skip this error message? I did some research and found begin/rescue. But I don't know how and where to put it.
It would really appreciate any help or advice.
This is because you are using + to implicitly concatenate the URL to your host, but at least for one post, #post.preview_image.try(:data).try(:url) is returning as nil.
You could fix it by using string interpolation like this:
%meta{:content => "https://www.joynus.com#{#post.preview_image.try(:data).try(:url)}", :name => "twitter:image"}
Or by explicitly converting to string with to_s like this:
%meta{:content => "https://www.joynus.com"+#post.preview_image.try(:data).try(:url).to_s, :name => "twitter:image"}

How to list all child objects for all parent objects?

What I have at the moment is pretty standard set of code, where all child objects can be list under only their parent objects.
customer.rb
class Customer < ApplicationRecord
has_many :bookings, dependent: :delete_all
end
booking.rb
class Booking < ApplicationRecord
belongs_to :customer
has_many_attached :images
end
routes.rb
Rails.application.routes.draw do
resources :customers do
resources :bookings
end
end
bookings_controller.rb
This has been automatically generated. I only removed comments and json
related lines.
class BookingsController < ApplicationController
before_action :set_customer
before_action :set_booking, only: %i[show edit update destroy]
def index
#bookings = Booking.all.with_attached_images
end
def show; end
def new
#booking = #customer.bookings.build
end
def edit; end
def create
#booking = #customer.bookings.build(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #customer, notice: 'Booking was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #booking.update(booking_params)
format.html { redirect_to [#customer, #booking], notice: 'Booking was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#booking.destroy
respond_to do |format|
format.html { redirect_to customer_bookings_url, notice: 'Booking was successfully destroyed.' }
end
end
private
def set_customer
#customer = Customer.find(params[:customer_id])
end
def set_booking
#booking = #customer.bookings.find(params[:id])
end
def booking_params
params.require(:booking).permit(:name, :category, :rooms, :wifi, :phone, :address, :description, :available, :check_in, :check_out, :customer_id, images: [])
end
end
I want to list all child objects for all parent objects.
I guess, I will have to modify routes as follows
routes.rb
Rails.application.routes.draw do
root 'customers#index'
resources :customers do
resources :bookings
end
resources :bookings
end
I will also need to modify bookings_controller.rb
By commenting out the line before_action :set_customer, otherwise I will get an error like Couldn't find Customer without an ID
And I will have to put #customer = Customer.find(params[:customer_id]) for all methods except index. Which means I won't be following DRY concept...
Any other better approach to solve this?
Your approach is the best already in my opinion, just need to utilize Rails helpers correctly to keep your code DRY.
By commenting out the line before_action :set_customer, otherwise I
will get an error like Couldn't find Customer without an ID
And I will have to put #customer = Customer.find(params[:customer_id])
for all methods except index. Which means I won't be following DRY
concept...
NO you don't have to.
If the index action of customers/bookings_controller is not used anywhere else then just remove that action from the controller file and specify the same in the route file as:
resources :customers do
resources :bookings, except: :index
end
If the index action is still being used in other places then Rails callbacks can be declared with except option as below to specify that the set_customer will be called for all actions except the index.
before_action :set_customer, except: :index
More about Rails Controller Callback options here
Other points that you may want to check:
dependent: :delete_all. With this, there will be orphan active_storage_attachments records in your db when you delete a customer. Because it triggers the callback that deletes only the associated bookings when leave the attached images of those bookings untouched. Reference
resources :bookings (last line of your route file). If you only have the index action in the controller, you should declare the same here also as resources :bookings, only: :index

CanCanCan refuses to load collection for :create

In my PromoCodesController I have this code:
load_and_authorize_resource :restaurant, find_by: :permalink
load_resource :discount, through: :restaurant
load_resource :promo_code, collection: [:create], through: :discount
It should be good since in #index, it loads the collection #promo_codes and in #create it loads #promo_code.
But it does not load the collection #promo_codes in #create. Where is the problem? In the documentation it says:
:collection argument: Specify which actions are resource collection actions in addition to :index.
Thank you
It's not working because Cancancan's method load_resource (controller_resource_loader.rb) assumes
only one resource variable to be set at a time: either resource_instance or collection_instance.
Your load_resource collection: [:create] can load #promo_codes in #create action via monkey patch to CanCan::ControllerResourceLoader:
# config/initializers/cancan.rb
module CanCan
module ControllerResourceLoader
def load_resource
return if skip?(:load)
# Original condition has been split into two separate conditions
if load_instance?
self.resource_instance ||= load_resource_instance
end
if load_collection?
self.collection_instance ||= load_collection
end
end
end
end
The common way in which this patch works is a create form integrated into index action:
class TicketsController < ActionController::Base
load_and_authorize_resource collection: [:create]
def index
#ticket = Ticket.new
end
def create
if #ticket.valid?
#ticket.create_for_user! params[:message]
redirect_to ticket_path(#ticket)
else
# #tickets are also defined here
render :index
end
end
end

render multiple queries as json in rails controller

I have two rails controller actions:
def show
#project = Project.find(params[:id])
render json: #project,
:only => [:id, :compilation_id],
:methods => :track_name,
:include => {
:user => { :only => [:id, :email] }
}
end
def list_users
render json: User.select(:id, :email)
end
I would like to render them both in one response. What is the best way to go about doing this? I tried using the to_json method as described here but I read that that method is deprecated and I also noticed that it escapes the content which seems to be unnecessary. Any help is appreciated.
For the cases where you need json structures complicated enough for to_json to look readable, I recommend to use active_model_serializers gem.
You can then define two serializer classes like this:
class ProjectSerializer < ActiveModel::Serializer
attributes :id, :compilation_id
has_many :users
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
end
And then in your controller:
class ProjectsController < ApplicationController
def show
#project = Project.find(params[:id])
render json: #project, serializer: ProjectSerializer, status: 200
end
end
As a bonus track, you can even cache the response!
The solution, of course, was pretty simple:
project = Project.select(:id, :compilation_id, :user_id, :genre_id, :ordering).find(params[:id])
render json: { :project => project,
:users => User.select(:id, :email),
:genres => Genre.select(:id, :name),
:track_name => project.track_name
}

handling exception in nested resources with Mongoid::Errors::DocumentNotFound rails 3.1

I have in my application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
rescue_from Mongoid::Errors::DocumentNotFound, :with => :render_not_found
def render_not_found
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
end
Then I call
This code working fine for example in my routes.rb:
resources :posts
The problem is that If I have a nested resource like this in routes.rb:
resources :users do
resources :posts
end
I have this in posts_controller.rb
class PostsController < ApplicationController
end
Now with this parent :users does not work!. I have that write in every actions from posts_controller.rb this nested resource the next for working fine e.g..
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
rescue
render_not_found
end
In your controller code here,
class Users::PostsController < ApplicationController
end
you have Users::Posts, but you are not specifying the location of the PostsController in the routes above.

Resources