Together网站搭建之踩坑系列7

这是功能实现的第六篇,扯一扯如何实作活动申请.

完整作品源码及效果,看这里作品网站, 作品源码

目录

正文

具体说,是实作以下两个功能:

  • 用户可申请参与活动
    • 如果活动已过期,则无法申请,显示已结束;
    • 如果人数已满,则显示活动已经满员,报名截止;
    • 既未过期,也没有满员,则用户可申请参与活动;
  • 用户可以查看自己的申请列表

一步步来:

BTW,请无视CSS部分,只讲如何实作功能。

Step1、 用户可以申请参与活动

效果图:

  • 新建model apply_event,终端:

    rails g model apply_event user_id:integer event_id:integer
    
  • 建立apply_event, user, event三者之间的关系:

    • app/models/apply_event.rb中添加:

      class ApplyEvent < ApplicationRecord
       + belongs_to :user
       + belongs_to :event
      end
      
    • app/models/event.rb中添加:

      ......
      has_many :apply_events
      has_many :appliers, :through => :apply_events, :source => :user
      ......
      
    • app/models/user.rb中添加:

      ......
      has_many :apply_events
      has_many :applied_events, through: :apply_events, source: :event
      ......
      
  • 用户可以申请参加活动或取消申请

    • app/models/user.rb中添加:

        ......
        def apply_already?(event)
          applied_events.include?(event)
        end
      
        def apply!(event)
          applied_events << event
        end
      
        def cancel!(event)
          applied_events.delete(event)
        end
        ......
      

    • app/controllers/events_controller.rb中添加:

      class EventsController < ApplicationController
        ......
        def apply
          @event = Event.find(params[:id])
          type = params[:type]
          if type == "apply"
            current_user.apply!(@event)
          else type == "cancel"
            current_user.cancel!(@event)
          end
          redirect_to :back
        end
        ......
      end
      

      申请参加活动,需要用户在登录状态下,修改app/controllers/events_controller.rbbefore_action :authenticate_user!部分,加上apply

      - before_action :authenticate_user!, only: [:new, :create,.....]
      + before_action :authenticate_user!, only: [:apply,:new, :create,.....]
      
    • 修改config/routes.rb, 添加如下代码:

        ......
        resources :events do
          ......
        + put :apply, on: :member
        end
        ......
      
    • 修改app/views/events/show.html.erb, 添加如下代码:

      ......
      <% if @event.end_time < Time.now %>
          <label class="label label-default event-over">活动已结束</label>
      <% elsif @event.appliers.count >= @event.limited_num %>
          <label class="label label-default event-over">活动已满员</label>
      <% else %>
        <% if current_user && current_user.apply_already?(@event) %>
          <%= link_to("取消申请", apply_event_path(@event, type: "cancel"), method: :put, class: "btn btn-default event-apply")%>
        <% else %>
          <%= link_to("申请赴约", apply_event_path(@event, type: "apply"), method: :put, class: "btn btn-success event-apply")%>
        <% end %>
      <% end %>
      ......
      

      现在看看,可以实现申请及取消申请了。但是,你很快就会发现,点击按钮后页面会refresh一下,这个不好不好,我们请上ajax。

  • 使用ajax来优化

    • 新增app/views/events/_apply.html.erb, app/views/events/apply.js.erb

    • 修改app/views/events/show.html.erb, 给这块要动态变化的区域加上ID

      + <div class="col-md-2" id="apply-<%= @event.id %>">
      -              <% if @event.end_time < Time.now %>
      -                  <label class="label label-default event-over">活动已结束</label>
      -              <% elsif @event.appliers.count >= @event.limited_num %>
      -                  <label class="label label-default event-over">活动已满员</label>
      -              <% else %>
      -                <% if current_user && current_user.apply_already?(@event) %>
      -                  <%= link_to("取消申请", apply_event_path(@event, type: "cancel"), method: :put, class: "btn btn-default event-apply")%>
      -                <% else %>
      -                  <%= link_to("申请赴约", apply_event_path(@event, type: "apply"), method: :put, class: "btn btn-success event-apply")%>
      -                <% end %>
      -              <% end %>
      +              <%= render :partial => "apply", :locals => {:event => @event }%>
      + </div>
      
    • 编辑app/views/events/_apply.html.erb, 添加如下代码:

      <% if event.end_time < Time.now %>
        <label class="label label-default event-over">活动已结束</label>
      <% elsif event.appliers.count >= event.limited_num %>
        <label class="label label-default event-over">活动已满员</label>
      <% else %>
        <% if current_user && current_user.apply_already?(event) %>
          <%= link_to apply_event_path(event, type: "cancel"), method: :put, :remote => true do %>
          <span class="btn btn-default event-apply">取消申请</span>
          <% end %>
        <% else %>
          <%= link_to apply_event_path(event, type: "apply"), method: :put, :remote => true do %>
          <span class="btn btn-success event-apply">申请赴约</span>
          <% end %>
        <% end %>
      <% end %>
      
    • 编辑app/views/events/apply.js.erb, 添加如下代码:

      str = "<%=j render :partial => "apply", :locals => {:event => @event } %>";
      $("#apply-<%= @event.id %>").html(str);
      
    • 编辑app/controllers/events_controller.rb, 拿掉apply的redirect_to

        ......
        def apply
          ......
          # redirect_to :back
        end
        ......
      

    现在试试,可以快速申请,快速取消啦,棒棒哒!!

Step2、 用户可以查看自己的申请列表

效果图:

这部分就比较简单啦。

  • 新增controller,终端运行:

    rails g controller account::apply_events
    
  • 修改config/routes.rb, 添加如下代码:

      ......
      namespace :account do
        ......
      + resources :apply_events
      end
      ......
    
  • 编辑app/controllers/account/apply_events_controller.rb,添加

    class Account::ApplyEventsController < ApplicationController
      before_action :authenticate_user!
    
      def index
        @events = current_user.applied_events
      end
    end
    
  • 新增app/views/account/apply_events/index.html.erb, 添加如下代码:

<h1 class="text-center">我的申请</h1>

<div class="col-md-10 col-md-offset-1" style="margin-top: 20px;">
  <table class="table table-bordered">
    <thead>
      <tr>
        <th>活动名称</th>
        <th>开始时间</th>
        <th>结束时间</th>
        <th>地点</th>
        <th>主办方</th>
        <th>类别</th>
        <th>人数限额</th>
        <th>剩余名额</th>
        <th>状态</th>
      </tr>
    </thead>
    <tbody>
      <% @events.each do |event| %>
        <tr>
          <td>
            <% link_to event_path(event)%>
             <% if event.logo.present? %>
              <%= link_to image_tag(event.logo.thumb.url, class:"event_logo_sm")%>
            <% else %>
              <%= link_to image_tag("http://placehold.it/100x100&text=No Pic", class: "event_logo_sm")%>
            <% end %>
            <%= link_to(event.title, event_path(event)) %></td>
          <td><%= event.start_time %></td>
          <td><%= event.end_time %></td>
          <td><%= event.address %></td>
          <td><%= event.sponsor %></td>
          <td><%= event.category.name %></td>
          <td><%= event.limited_num %></td>
          <td><%= event.limited_num - event.appliers.count %></td>
          <td><%= t(event.status, :scope => "event.status") %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>


<!-- 分页 -->
<div class="text-center">
  <%= will_paginate @events, renderer: BootstrapPagination::Rails, :previous_label => '上一页', :next_label => '下一页' %>
</div>
  • 编辑app/views/common/_navbar.html.erb,加上我的申请入口:

    ......
    + <li><%= link_to(" 我的申请",account_apply_events_path(current_user), class: "btn btn-default")%></li>
    ......
    

试试看,可以啦!