[Rails Level 2] RENDERING EXTREMITIES -- Ex (Return in Json, resoure route)
RENDER
Complete the method below so that if the ammo is low it will render the fire_and_reload view, otherwise it should render the fire_weapon view.
1. In this case, render will take a single argument that maps to the name of the view. 2. If you don't call render, Rails will automatically render the view of the same name as the action 3. The correct answer should be: class WeaponsController < ApplicationController def fire_weapon @weapon = Weapon.find(params[:id]) @weapon.fire! if @weapon.low_ammo? render :fire_and_reload end end end
CUSTOM RESOURCE ROUTES
Create two custom member routes on the weapons resource, so you have a put method calledtoggle_condition and a put method called reload.
1. To add routes to the :weapons resource pass a block, like this: resources :weapons do # custom routes go here end 2. To add a custom route, call the HTTP method and then pass in the name, like this: resources :weapons do put :toggle_condition, on: :member end RailsForZombies::Application.routes.draw do resources :zombies do resources :weapons do put :toggle_condition, on: :member put :reload, on: :member end end end
RENDER JSON
Complete the create method below. When @weapon.save is successful it should render the @weapon object in JSON, have status :created, and set the location to the @weapon's show url. When @weapon.save fails it should return the @weapon.errors and have the status:unprocessable_entity.
1. To render a @weapon as json, you can do this: render json: @weapon 2. render takes the options :status and :location, like this: render json: @weapon, status: :created, location: @weapon class WeaponsController < ApplicationController def create @weapon = Weapon.new(params[:weapon]) if @weapon.save render json: @weapon, status: :created, location: @weapon else render json: @weapon.errors, status: :unprocessable_entity end end end
RENDER JSON W/OPTIONS
Complete the controller so that it returns in JSON only the amount of ammo which is left in the weapon. If the ammo has less than 30 bullets it should return the status code :ok, and if not it should return the status code :unprocessable_entity.
1. To limit the json that is output, you'd use to_json and pass in the :only option, like this: @weapon.to_json(only: :ammo) 2. render takes the option :status, like this: render json: @weapon.to_json(only: :ammo), status: :ok class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) render json: @weapon.to_json(only: :ammo), status: :ok else render json: @weapon.to_json(only: :ammo), status: :unprocessable_entity end end end
MORE TO JSON OPTIONS
Modify the show action so that the JSON it renders includes the zombie record the @weapon belongs to. Also make it exclude the :id, :created_at, and :updated_at fields.
1. To exclude some data in a to_json call, use :except, like this: @weapon.to_json(except: [:updated_at, :id, :created_at]) 2. To include an association in a to_json call, use the :include option, like this: @weapon.to_json(except: [:updated_at, :id, :created_at], include: :zombie) class WeaponsController < ApplicationController def show @weapon = Weapon.find(params[:id]) render json: @weapon.to_json(except: [:id, :created_at, :updated_at], include: :zombie) end end
AS JSON
Edit the as_json method so the Zombie class only returns the zombie's name and weapons (useinclude). Only return the weapon's name and ammo.
class Zombie < ActiveRecord::Base has_many :weapons def as_json(options=nil) super (options || {only: :name, include: {weapons: {only: [:name, :ammo]}}}) end end
LINK REMOTE
Modify the show.html.erb view below so that both the Toggle link and the Reload form use AJAX. All you need to do is add the option that makes them ajaxified.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
1. Use the remote option to make a link use Ajax, like this: link_to "Toggle", toggle_condition_weapon_path(@weapon), remote: true <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_weapon_path(@weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <%= form_for @weapon, url: reload_weapon_path(@weapon), remote: true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload"%> </div> <% end %>
AJAX RESPONSE
Modify the toggle_condition action so that it responds to JavaScript, and complete thetoggle_condition.js.erb using jQuery to update the condition span with the @weapon's changed condition and make it highlight.
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> </ul>
Answer:
weapons_controller.rb:
class WeaponsController < ApplicationController def toggle_condition @weapon = Weapon.find(params[:id]) @weapon.toggle_condition respond_to do |format| format.html { redirect_to @weapon, notice: 'Changed condition' } format.js end end end
toggle_condition.ks.erb:
1. To get an action to respond to an Ajax request, you need to add format.js, like this: respond_to do |format| format.html { redirect_to @weapon, notice: 'Changed condition' } format.js end 2. You can add javascript code with erb tags in toggle_condition.js.erb, like this: $('#condition').text("<%= @weapon.condition %>").effect("highlight") //=require jQuery_ui $("#condition").text("<%= @weapon.condition %>").effect('highlight')
AJAX RESPONSE II
Now write the controller and JavaScript code needed to properly reload the weapon using the ajaxified form. In the reload.js.erb use jQuery to update the #ammo text to the current @weapon.ammo value and if the ammo value is over or equal to 30, fadeOut the #reload_form div.
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <div id="reload_form"> <%= form_for [@user, @weapon], url: reload_user_weapon_path(@user, @weapon), remote:true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload" %> </div> <% end %> </div> <%= link_to 'Edit', edit_weapon_path(@weapon) %> | <%= link_to 'Back', weapons_path %>
Answer:
#weapons_controller.erb class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) respond_to do |format| if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) format.json { render json: @weapon.to_json(only: :ammo), status: :ok } format.html { redirect_to @weapon, notice: 'Weapon ammo reloaded' } else format.json { render json: @weapon.to_json(only: :ammo), status: :unprocessable_entity } format.html { redirect_to @weapon, notice: 'Weapon not reloaded' } end format.js end end end
$("#ammo").text("<%= @weapon.ammo %>") <% if @weapon.ammo >= 30%> $("#reload_form").fadeOut(); <% end %>
COFFEESCRIPT
Instead of returning jQuery which gets executed on the client-side, lets write the ajax request in CoffeeScript communicating with JSON. It should do the same thing as the last challenge, updating & highlighting the ammo, and fading out the form (hint: fade out the wrapper element) if ammo is equal or above 30.
Tip for your ajax form: data: {ammo_to_reload: ammo}.
class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) respond_to do |format| if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) format.json { render :json => @weapon.to_json(:only => :ammo), status: :ok } format.html { redirect_to @weapon, notice: 'Weapon ammo reloaded' } else format.json { render :json => @weapon.to_json(:only => :ammo), status: :unprocessable_entity } format.html { redirect_to @weapon, notice: 'Weapon not reloaded' } end format.js end end end
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <div id="reload_form"> <%= form_for [@user, @weapon], url: reload_user_weapon_path(@user, @weapon), remote:true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload" %> </div> <% end %> </div> <%= link_to 'Edit', edit_weapon_path(@weapon) %> | <%= link_to 'Back', weapons_path %>
Answer:
$(document).ready -> $('div#reload_form form').submit (event) -> event.preventDefault() url = $(this).attr('action') ammo = $('#ammo_to_reload').val() $.ajax type: 'put', data: {ammo_to_reload: ammo}, url: url, dataType: 'json', success: (json)-> $("#ammo").text(json.ammo).effect('highlight') if json.ammo >= 30 $("#reload_form").fadeOut()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具