A user can log-in (devise gem), create a text post, & tag that post (via acts-as-taggable-on gem). If a tag is used more than once across posts, the CSS of that tag changes. In the example below, for instance, the underline style on #foobar disappears. However, as it stands, this is happening across user accounts. This means the tags a user inputs to tag their posts are not unique to their account. In other words, if User1 tags #foobar and after, on a separate account, User2 also tags #foobar - the underline goes away on both user accounts. My goal is to make the tags a user inputs in the posting form unique to that user.
Example:
User1 Account
https://i.sstatic.net/dgIQ8.jpg
User2 Account
I have tried lots of solutions - none of which are working!! Please help!
posts_controller.rb
class PostsController < ApplicationController
def index
if params[:tag]
@posts = current_user.posts.tagged_with(params[:tag]).order(created_at: :desc)
else
@posts = current_user.posts.includes(:things).all.order(created_at: :desc)
end
end
def new
@post = current_user.posts.build
end
def create
@post = current_user.posts.build(post_params)
if @post.save
redirect_to '/posts'
else
render 'new'
end
end
new.html.erb
<button id='addtext'>text</button>
<%= form_for @post, html: { multipart: true } do |f| %>
<%= f.text_field :tag_list %>
<%= f.fields_for :things do |ff| %>
<% end %>
<%= f.submit %>
<% end %>
index.html.erb
<div id="posts">
<%= render @posts %>
</div>
_post.html.erb
<div class="post">
<%= raw post.tags.order("taggings_count DESC").map {|t| link_to t.name, tag_path(t.name), class: css_class_for_tag(t.taggings_count)}.join(' ') %>
<% post.things.each do |thing| %>
<%= thing.try(:text) %>
<% end %>
</div>
post_helper.rb
module PostsHelper
def css_class_for_tag count
case count
when 1
'new_tag'
else
'used_tag'
end
end
end
post model
class Post < ActiveRecord::Base
acts_as_taggable
ActsAsTaggableOn.delimiter = ' '
ActsAsTaggableOn.force_lowercase = true
belongs_to :user
has_many :things, dependent: :destroy
accepts_nested_attributes_for :things, allow_destroy: true
end
thing model
class Thing < ActiveRecord::Base
belongs_to :post
has_attached_file :image, styles: { small: "300x300>", medium: "600x600>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
user model
class User < ActiveRecord::Base
acts_as_tagger
has_many :posts
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Schema
ActiveRecord::Schema.define(version: 20160303110608) do
create_table "posts", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "taggable_id"
t.string "taggable_type"
t.integer "tagger_id"
t.string "tagger_type"
t.string "context", limit: 128
t.datetime "created_at"
end
add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", force: :cascade do |t|
t.string "name"
t.integer "taggings_count", default: 0
end
add_index "tags", ["name"], name: "index_tags_on_name", unique: true
create_table "things", force: :cascade do |t|
t.text "text"
t.integer "post_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "order"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
One way of doing it:
tag_counts = ActsAsTaggableOn::Tag.joins(:taggings).
where(taggings: { taggable_type: "Post", taggable_id: current_user.post_ids }).
group("tags.id").count
Gives you something like this:
{ 7=>2, 1=>2, 5=>4 }
The first number is the tag id, the second number is the number of occurrences of that tag for current_user.
Now you can do this:
<div class="post">
<%= raw post.tags.map{ |t| [t.name, tag_counts[t.id]] }.sort_by{ |t| -t[1] }.
map{ |t| link_to t[0], tag_path(t[0]), class: css_class_for_tag(t[1])}.join(' ') %>
</div>
This can be written more expressively, but it gets longer than... ;-) Basically we loop over the post's tags, just as we did before, but then connect each tag with its count specific to current_user in the first map statement. Then we sort by the count, in reverse order. And in the final map statement we generate the links, as we did before, just using the user specific count again.