4

How can we give the user the option to make activities private? This would give users privacy for posts they want for their eyes only.

I was told this code isn't working because it might have something to do with "not setting up the 'private' checkbox to work correctly", yet the private checkbox works for hiding submissions on the public profiles (just not on the activities feed).

class ActivitiesController < ApplicationController
  def index #Added .public
    @activities = Activity.visible.order("created_at desc").where(user_id: current_user.following_ids)
  end
end


class Activity < ActiveRecord::Base
  belongs_to :user
  has_many :comments, as: :commentable
  belongs_to :trackable, polymorphic: true
  scope :visible, ->{ where(:hidden => false) }

  def visible?
    !hidden
  end
end

create_table "activities", force: true do |t|
  t.boolean "hidden", default: false
  t.integer  "user_id"
  t.string   "action"
  t.integer  "trackable_id"
  t.string   "trackable_type"
  t.datetime "created_at",     null: false
  t.datetime "updated_at",     null: false
end

And in one of the _forms, such as @valuations or @goals, is where the user can make the distinction via his submission:

 <%= button_tag(type: 'submit', class: "btn", id: "gold")  do %>
   <span class="glyphicon glyphicon-plus"></span> Public
 <% end %>

 <%= button_tag(type: 'submit', class: "btn") do %>
   <% :hidden %><span class="glyphicon glyphicon-plus"></span> Private
 <% end %>

Thank you!

Community
  • 1
  • 1
  • my suggestion about the checkbox was a guess based on not actually seeing all your code. You say it hides them but not on the feed? Which ones aren't being shown? Can you go look them up in the db and see what value they have for their "private" boolean? Perhaps they aren't getting set to "false" properly, but are either true or nil... in which case - yes, there's something wrong with the checkbox... you need a default value. – Taryn East Apr 22 '15 at 23:24
  • Hey thanks for meeting me over here @TarynEast! I see we keep editing each other's entries. The reason I used `.public_activities` instead of `.public` is because I get this error with it: `You tried to define a scope named "public" on the model "Activity", but Active Record already defined a class method with the same name.` Am I wrong to switch it or do you have a better solution? I think with rails 4 they reserve that word. –  Apr 22 '15 at 23:47
  • Ah right... yep that's fair. Pick another name for it - but preferably avoid "smurf naming convention" (where the "Smurf" class has a "public_smurfs" method) ;) – Taryn East Apr 23 '15 at 00:09
  • yeah, just thinking, you probably don't wanna mess with "private" also - that's a special word in ruby (for making methods visible outside of the instance). – Taryn East Apr 23 '15 at 00:13
  • Note: Rails has a lot of "special" names that aren't written down anywhere... that correspond to things you probably shouldn't accidentally overwrite with your own methods. i keep meaning to write a blogpost that lists all the most dangerous ones. – Taryn East Apr 23 '15 at 00:42
  • Quick chat @TarynEast? http://chat.stackoverflow.com/rooms/75987/room-for-rubyonrailsbeginner-and-taryn-east –  Apr 23 '15 at 00:48
  • I don't really have time for that... If you have questions... feel free to ask them and I'll get to them in my gaps between working ;) – Taryn East Apr 23 '15 at 00:54
  • haha no problem @TarynEast that's a good blog post idea if you find time away from work and helping me ;) I've switched over the names to visible & hidden. By doing so only one valuation shows now in the users profile regardless of how many are submitted as visible or hidden. I've been trying to fix this problem for the past 40 min to get back to the original problem posed here. I'm thinking that their is some sort of naming collision preventing `def visible_valuations valuations.find(&:visible?) end` from listing out all the valuations in the profile `@valuations = @user.visible_valuations` –  Apr 23 '15 at 01:40
  • Can you please check what the values are in the db for these items? Make certain it's not that the boolean is set to nil – Taryn East Apr 23 '15 at 02:09
  • No @TarynEast doesn't say nil: [3] pry(main)> Valuation.find(2) Valuation Load (0.1ms) SELECT "valuations".* FROM "valuations" WHERE "valuations"."id" = ? LIMIT 1 [["id", 2]] => # [4] pry(main)> Valuation.find(3) Valuation Load (0.1ms) SELECT "valuations".* FROM "valuations" WHERE "valuations"."id" = ? LIMIT 1 [["id", 3]] => # –  Apr 23 '15 at 02:24
  • 1
    sorry that's impossible to read... also those a valuations, not activities... I'm confused. Also looking back over previous comment.s you really don't need to do this: `def visible_valuations valuations.find(&:visible?) end` - just use the "visible" scope. `a_model.thingies.visible` should work, if you have a scope called `visible` it will work on any collection - not just on the `Thingie` class, but also on `has_many` collections. In this case, say: `user.valuations.visible` – Taryn East Apr 23 '15 at 03:59
  • 1
    Thanks @TarynEast for your last comment! That helped put me back on the right track! I renamed and reworked a lot so I thought it would be better to start with a fresh question: http://stackoverflow.com/questions/29834607/how-to-conceal-from-feed –  Apr 23 '15 at 21:28

1 Answers1

0

I would use an enum column instead. Enums give you tons of functionality such as scopes, interrogation and even bang methods to change the status. But most of all enums are built to extend - lets say you want to add the functionality that users can have posts that are only viewable by friends - adding an additional state to an enum is easy!

First we add a database column. Run:

rails g migration AddVisiblityToActivities visibility:integer:index

Then edit the migration to add a default:

class AddVisibilityToActivities < ActiveRecord::Migration
  def change
    t.integer :visibility, index: true, default: 0
  end
end

Run the migration with rake db:migrate. Then we need to add the enum mappings to the Activity model:

class Activity < ActiveRecord::Base
  belongs_to :user
  has_many :comments, as: :commentable
  belongs_to :trackable, polymorphic: true

  # change the order if you want to default to private!
  enum visibility: [:visible, :hidden]

  default_scope { visible.order('created_at DESC') }
end

Note that we also add a default scope. With that we can really simplify the query in our controller:

class ActivitiesController < ApplicationController
  def index #Added .public
    @activities = Activity.where(user: current_user.following)
    # note that you don't have to use ids when creating a
    # where clause from an association. Rails does the work for you
  end
end

The easiest way to let users alter the visibility when creating/updating records is to use a select:

<div class="field">
  <%= f.label :visibility %>
  <%= f.select :visibility, Activity.visibilities.keys.map(&:titleize) %>
</div>

Just remember to whitelist the visibility property!

# app/controllers/activities_controller.rb

# ...

def create
  @activity = Activity.new(activity_params) do |a|
    a.user = current_user
  end

  # ...
end

# ...

def activity_params
  params.require(:activity).permit(:visibility)
end
max
  • 96,212
  • 14
  • 104
  • 165