I have the following function in controller
def by_xy
#obj = BldPoly::find_by_xy(:x => params['x'], :y => params['y'])
respond_to do |format|
format.html { render :layout => false }
format.xml { render :layout => false }
format.json { render :layout => false }
end
and planning to write the automatic test in the following way
xml = nil
get :by_xy, {:x => 4831, :y => 3242, :format => :json}
assert_nothing_thrown { xml = REXML::Document.new(#response.body) }
td = REXML::XPath.first(xml, "//result/item")
assert_equal need_value, td.value
and I get
Completed in 50ms (View: 0, DB: 230) | 406 Not Acceptable [http://test.host/search/by_xy/4831/3242.json]
when I missed format in testing code - all works correctly,
how should I write the test?
I figured this out, actually; this is how it should be
get :by_xy, {:x => i[:x], :y => i[:y]}, :format => :json
For rails 5.1, when doing a post, I had to include the format attribute inside of my params hash
share_params = {
email: nil,
message: 'Default message.'
format: :json
}
post image_share_path(#image), params: share_params
assert_response :unprocessable_entity
If not I would get the error ActionController::UnknownFormat inside of my create controller
def create
#image = Image.new(image_params)
if #image.save
flash[:success] = 'Your image was saved successfully.'
redirect_to #image
else
respond_to do |format|
format.json do
render json: { #image.to_json },
status: :unprocessable_entity
end
end
end
Related
I have the following code segment
def range
respond_to do |format|
if params[:start] && params[:end]
begin
dstart = Time.parse(params[:start])
dend = Time.parse(params[:end])
rescue => e
format.json { render :json => { :status => :unprocessable_entity, :error => e.message }} and return
end
...
And it works totally fine and makes it to the stuff at the bottom...
...
format.json { render :json => { :status => :ok, :posts => #res.to_json(:only => [:date, :content, :user_id]) } }
else
format.json { render :json => { :status => :unprocessable_entity, :error => "must have a _start_ and _end_ date" } }
...
The problem is when an exception occurs and the rescue section is called, Rails does not respond with json but instead tells me "Template Missing." Is something wrong with my syntax?
D'oh, turns out I don't need the format.json bit. Why, exactly, though?
Consider this example regarding show action to understand the error
class ModelsController
.
.
def show
#model = Model.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
end
In this case, if the request is of type html then rails by convention searcher for a file
app/views/models/show.html.erb.
But if the request is of type js then rails will search for app/views/models/show.js.erb.
If these files does not exist then rails will throw template missing error
so if you are only responding to json then you can do
respond_to do |format|
format.json do
begin
..
rescue
render :json => { }
end
end
How do I accept an array of JSON objects on my rails site? I post something like
{'team':{'name':'Titans'}}
However, if I try to post a JSON with an array of objects. It only saves the 1st object.
{'team':[{'name':'Titans'},{'name':'Dragons'},{'name':'Falcons'}]}
My goal is to send multiple 'teams' in 1 JSON file. What do I have to write on the Rails side?
On the rails side, I have something like
def create
#team = Team.new(params[:team])
#team.user_id = current_user.id
respond_to do |format|
if #team.save
format.html { redirect_to(#team, :notice => 'Team was successfully created.') }
format.json { render :json => #team, :status => :created, :location => #team }
else
format.html { render :action => "new" }
format.json { render :json => #team.errors, :status => :unprocessable_entity }
end
end
end
Do I take the params: and for each element, create a new team or something? I'm new to ruby so any help would be appreciated.
Let me assume you post
{'team':[{'name':'Titans'},{'name':'Dragons'},{'name':'Falcons'}]}
Then your params will be
"team" => {"0"=>{"chapter_name"=>"Titans"}, "1"=>{"chapter_name"=>"Dragons"}, "2"=>{"chapter_name"=>"Falcons"}}
My idea is
def create
#insert user id in all team
params[:team].each_value { |team_attributes| team_attributes.store("user_id",current_user.id) }
#create instance for all team
teams = params[:team].collect {|key,team_attributes| Team.new(team_attributes) }
all_team_valid = true
teams.each_with_index do |team,index|
unless team.valid?
all_team_valid = false
invalid_team = teams[index]
end
end
if all_team_valid
#teams = []
teams.each do |team|
team.save
#teams << team
end
format.html { redirect_to(#teams, :notice => 'Teams was successfully created.') }
format.json { render :json => #teams, :status => :created, :location => #teams }
else
format.html { render :action => "new" }
format.json { render :json => invalid_team.errors, :status => :unprocessable_entity }
end
end
Currently I verify that there are no duplicated Members when trying to create a new Member and add it to a Team.
members_controller.rb
def create
#team = current_team
player = Player.find(params[:player_id])
#member = #team.add_player(player.id)
respond_to do |format|
if #member.save
format.html { redirect_to(#team, :notice => 'Member was successfully added.') }
format.js { #current_member = #member }
format.xml { render :xml => #member,
:status => :created, :location => #member }
else
format.html { redirect_to(#team, :notice => 'Member already exists.') }
format.xml { render :xml => #member.errors,
:status => :unprocessable_entity }
end
end
end
team.rb
def add_player(player_id)
current_member = members.build(:player_id => player_id)
current_member
end
I want to add some logic to my add_player method in team.rb that checks various properties of the player that is being added. This action will require multiple failure messages, other than 'Member already exists.' How do I do this in the Model layer?
You can create custom errors on ActiveRecord models. These custom errors can have their own messages, which you can query in your controller if the save is not successful:
# app/models/team.rb
def add_player(player_id)
current_member = members.build(:player_id => player_id)
errors.add(:player_id, 'Custom error message here') if condition
errors.add(:base, 'Custom error message here') if condition
current_member
end
# app/controllers/members_controller.rb
def create
#team = current_team
player = Player.find(params[:player_id])
#member = #team.add_player(player.id)
respond_to do |format|
if #member.save
format.html { redirect_to(#team, :notice => 'Member was successfully added.') }
format.js { #current_member = #member }
format.xml { render :xml => #member,
:status => :created, :location => #member }
else
format.html { redirect_to(#team, :notice => #member.errors.full_messages) }
format.xml { render :xml => #member.errors,
:status => :unprocessable_entity }
end
end
end
More information on custom ActiveRecord validation errors here: http://api.rubyonrails.org/v2.3.8/classes/ActiveRecord/Errors.html#M001725
The controller logic to display all errors from base worked. However, I was not able to add errors from the add_player method as Ben suggested. I instead created separate custom validations as such:
Team.rb
validate validation_name
def validation_name
if condition
errors.add_to_base "Error Message"
end
end
This is the error:
ActionView::Template::Error (No route matches {:action=>"send_to_client", :controller=>"stages"}):
app/views/stages/_show.html.erb:13:in `_app_views_stages__show_html_erb__3606907191157577988_2203521120_617355097038007272'
app/controllers/stages_controller.rb:78:in `block (2 levels) in create'
app/controllers/stages_controller.rb:75:in `create'
This is line 13 in the _show.html.erb:
<%= link_to "<span class='icon send-to-client-icon' title='Send to Client'> </span>".html_safe, send_to_client_stage_path, :id => stage.id, :confirm => "This will send #{stage.name.capitalize} to #{stage.client.email}. Are you sure you are ready?" %>
This is my stages controller, create action:
def create
#stage = current_user.stages.create(params[:stage])
client = #stage.client
unless #stage.new_record?
respond_with(#stage, :status => :created, :location => #stage) do |format|
flash.now[:notice] = 'Stage was successfully created.'
format.html { redirect_to(#stage) }
format.js { render :partial => "stages/show", :locals => {:stage => #stage, :client => client}, :layout => false, :status => :created }
end
else
respond_with(#stage.errors, :status => :unprocessable_entity) do |format|
format.js { render :json => #stage.errors, :layout => false, :status => :unprocessable_entity }
format.html { render :action => "new" }
end
end
end
Stages Controller, send_to_client action:
def send_to_client
stage = Stage.find(params[:id])
ClientMailer.send_stage(stage).deliver
if ClientMailer.send_stage(stage).deliver
flash[:notice] = "Successfully sent to client."
redirect_to("/")
else
flash[:notice] = "There were problems, please try re-sending."
redirect_to("/")
end
end
You are missing the ID and need to pass the stage instance it in your send_to_client_stage_path call.
send_to_client_stage_path(stage)
instead of:
send_to_client_stage_path
def create
#asset = Asset.new(params[:asset])
respond_to do |format|
if params[:Filedata]
#asset = Asset.new :swf_uploaded_data => params[:Filedata]
#asset.user = current_user
#asset.save!
format.html { render :text => #asset.image.url(:thumb) }
format.xml { render :nothing => true }
else
if #asset.save
flash[:notice] = 'Created'
format.html { redirect_to(#asset) }
format.xml { render :xml => #asset, :status => :created, :location => #asset }
else
format.html { render :action => "new" }
format.xml { render :xml => #asset.errors, :status => :unprocessable_entity }
end
end
end
end
I am creating an upload status bar with swfupload. At the end of the upload I get a 406 error.
Not necessarily your answer but I had the same problem with Plupload and it happens that the request format is nil.
It might not be the best way but one could do the following:
request.format ||= :xml
in order to provide some default format in the method. Hope it can help others.