Reputation: 453
In my app I have a status model that also creates an activity item when a status is created. My activity model is polymorphic is belongs to a number of different models. Everything works fine, but I'm having trouble with my ajax status creation. On users' profile pages there's a status form and an activity list. I want users to be able to create a status through ajax and have the corresponding activity item appended to the list. Any ideas how I can do this? Thanks in advance.
statuses_controller.rb
class StatusesController < ApplicationController
before_filter :authenticate_member!, only: [:index, :new, :create, :edit, :update, :destroy]
before_filter :find_member
before_filter :find_status, only: [:edit, :update, :destroy]
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404', status: 404, formats: [:html]
end
def show
@status = Status.find(params[:id])
@commentable = @status
@comments = @commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
@comment = @commentable.comments.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
end
end
def new
@status = Status.new
@status.build_document
respond_to do |format|
format.html # new.html.erb
format.json { render json: @status }
format.js
end
end
def create
@status = current_member.statuses.new(params[:status])
respond_to do |format|
if @status.save
current_member.create_activity(@status, 'created')
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: @status.errors, status: :unprocessable_entity }
format.js
end
end
end
def destroy
@activity = Activity.find_by_targetable_id(params[:id])
@commentable = @status
@comments = @commentable.comments
if @activity
@activity.destroy
end
if @comments
@comments.destroy
end
@status.destroy
respond_to do |format|
format.html { redirect_to profile_path(current_member) }
format.json { head :no_content }
end
end
private
def find_member
@member = Member.find_by_user_name(params[:user_name])
end
def find_status
@status = current_member.statuses.find(params[:id])
end
end
activities_controller.rb
class ActivitiesController < ApplicationController
before_filter :authenticate_member!
before_filter :find_activity, only: [:destroy]
def index
params[:page] ||= 1
@activities = Activity.for_member(current_member, params)
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def destroy
@status = @activity.targetable
if @activity.targetable_type == 'Status'
@status.destroy
end
@activity.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
format.js
end
end
def upvote
@activity = Activity.find(params[:id])
if current_member.voted_up_on? @activity
@activity.unliked_by current_member
else
@activity.liked_by current_member
end
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
private
def find_activity
@activity = current_member.activities.find(params[:id])
end
end
activity.rb
class Activity < ActiveRecord::Base
belongs_to :member
belongs_to :targetable, polymorphic: true
acts_as_votable
self.per_page = 36
def self.for_member(member, options={})
options[:page] ||= 1
following_ids = member.following_members.map(&:id).push(member.id)
where("member_id in (?)", following_ids).
order("created_at desc").
page(options[:page])
end
end
profiles/show.html.erb
<% if @activities.count > 0 %>
<div id="media_query_stream">
<div id="activity_stream_wrap">
<%= render :partial => "activities/activities", locals: { activity: @activity} %>
</div>
</div>
<% else %>
<div class="none_message">
No Posts Yet
</div>
<% end %>
activities/_activities.html.erb
<% @activities.each do |activity| %>
<%= render partial: "activities/#{activity.targetable_type.underscore}/#{activity.action}", locals: { activity: activity } %>
<% end %>
activities/status/_created.html.erb
<div id="" class="list_act_wrap status_fil">
<div class="act_status_top">
<span class="">
<%= avatar_profile_link activity.member, :class => "act_av", title: activity.member.full_name, alt: activity.member.full_name %>
</span>
<span class="act_name">
<%= link_to activity.member.user_name, profile_path(activity.member) %>
</span>
<span class="meta">
<%= time_ago_in_words(activity.targetable.created_at) %>
</span>
<span class="act_title stat">
wrote a new <%= link_to 'Status', status_path(activity.targetable_id) %>
</span>
</div>
<div class="act_content">
<%= Rinku.auto_link(activity.targetable.content_html).html_safe %>
</div>
</div>
I tried to append the activity through ajax like so:
statuses/create.js.erb
$("#activity_stream_wrap").prepend("<%= escape_javascript(render :partial => 'activities/status/created', :locals => {:activity => @activity}) %>");
$('#stat_count').html("280");
$('#status_form')[0].reset();
But it throws an error like:
undefined method `member' for nil:NilClass
**EDIT**
Here's my create_activity method that actually creates the corresponding activity when a status is created. How do I get to this activity that's created so I can append it?
def create_activity(item, action)
activity = activities.new
activity.targetable = item
activity.action = action
activity.save
activity
end
Upvotes: 2
Views: 747
Reputation: 9173
If you look at your statuses/create.js.erb you are rendering your partial like this:
$("#activity_stream_wrap").prepend("<%= escape_javascript(render :partial => 'activities/status/created', :locals => {:activity => @activity}) %>");
Notice you are passing @activity in your partial but if you look at your create method in statuses controller you don't have an instance variable named @activity
Fix:
You need to create your activity and assign it to your instance variable like this:
def create
@status = current_member.statuses.new(params[:status])
respond_to do |format|
if @status.save
@activity = current_member.create_activity(@status, 'created') # you weren't assigning it to your instance variable
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: @status.errors, status: :unprocessable_entity }
format.js
end
end
end
Upvotes: 2