In my rails app I have users(authors),posts(articles),comments. If registered user write comment to article, I want to show his name beside his comment, if he isn't registered user I want to show "Anonymous" beside his comment. How can I do this?
comment model:
class Comment < ActiveRecord::Base
attr_accessible :post_id, :text
belongs_to :post
belongs_to :user
end
user model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
has_many :posts, :dependent => :destroy
has_many :comments, :dependent => :destroy
validates :fullname, :presence => true, :uniqueness => true
validates :password, :presence => true
validates :email, :presence => true, :uniqueness => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :fullname
end
post model:
class Post < ActiveRecord::Base
attr_accessible :text, :title, :tag_list
acts_as_taggable
validates :user_id, :presence => true
validates :title, :presence => true
validates :text, :presence => true
belongs_to :user
has_many :comments
end
view file (show.html.erb)
<h1><%= #post.title %></h1>
<p>
Created: <%= #post.created_at.strftime("%Y/%m/%d")%> by
<%= link_to #post.user.fullname, user_posts_path(#post.user) %>
</p>
<p><%=simple_format #post.text %></p>
<p>
Tags: <%= raw #post.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %>
</p>
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<p><%= comment.created_at.strftime("%Y/%m/%d") %>
by <%= HERE I NEED ADD SOMETHING%></p>
<p><%= comment.text %></p>
<p><%= link_to "Delete comment", [#post, comment], :method => :delete,
:confirm =>"Are you sure?"%></p>
<% end %>
<%= form_for [#post, #post.comments.build] do |f| %>
<p><%= f.text_area :text %></p>
<p><%= f.submit "Post comment" %></p>
<% end %>
<% if user_signed_in?%>
<p>
<%= link_to "Back", posts_path %>
<%= link_to "Edit", edit_post_path(#post) %>
<%= link_to "Delete", #post, :method => :delete, :confirm => "Are you sure?"%>
</p>
<% end%>
You can do this by calling the user method on the comment, and then name on that:
<%= comment.user.name %>
You can also define a to_s method in the User model:
def to_s
name
end
Which would mean you could get away with doing just this in the view:
<%= comment.user %>
If you're loading a whole bunch of comments, then I would recommend loading them this way:
#comments = Comment.includes(:user)
If you don't have that includes(:user) there, then Rails will issue a new query for every single comment to find that comment's user. Doing it this way makes Rails load all the users for all the comments upfront in just one query.
I think you want to create two assocations pointing to the same table:
class CreatePostss < ActiveRecord::Migration
def change
create_table :posts do |t|
t.text :text
t.references :user, index: true, foreign_key: true
t.references :author, index: true, foreign_key: { to_table: :users }
t.timestamps null: false
end
end
end
Here user_id references the target user of the post and author_id references the user writing the post. Both reference users.id.
Then create two belongs_to associations in your post model:
class Post < ApplicationRecord
belongs_to :user
belongs_to :author,
class_name: 'User',
inverse_of: :authored_posts
end
And two has_many associations in your User model:
class User < ApplicationRecord
# posts about this user
has_many :posts
# postss written by this user
has_many :authored_posts,
class_name: 'Post',
foreign_key: :author_id,
inverse_of: :author
end
Here is the controller
class PostsController < ApplicationController
before_action :set_user, only: [:new, :create]
# ...
def new
#post = #user.posts.new
end
def create
#post = #user.posts.new(post_params) do |c|
c.author = current_user
end
if #post.save
redirect_to doctor_path(id: #user.id)
else
render :new
end
end
private
def set_user
#user = User.find(params[:id])
end
# ...
end
To display posts you would do:
<% #user.posts.each do |post| %>
<div class="post">
<div class="body">
<%= post.body %>
</div>
<p class="author"><%= post.author.email %></p>
</div>
<% end %>
Related
So currently users can rsvp multiple times for the same event. That is obviously problematic for my website so I want it that a single user can only rsvp once for a specific post/event. After they have made their Rsvp I want the rsvp button to disappear. Heres is how my code is looking.
show.html.erb
id="notice"><%= notice %></p>
<p>
<strong>Date:</strong>
<%= #post.date %>
</p>
<p>
<strong>Name:</strong>
<%= #post.name %>
</p>
<p>
<strong>User_id:</strong>
<%= #post.user_id %>
</p>
<p><strong>Address:</strong> <%= #post.address %></p>
<p>
<strong>Description:</strong>
<%= #post.description %>
</p>
<p>
<strong>registered:</strong>
<%=#post.users.length%>
</p>
<% if current_user == #post.user %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%end%>
<%= link_to 'Back', posts_path %>
<div class="rsvp"><%= button_to "Rsvp now", rsvps_post_path(#post), class: "btn btn-primary" %></div>
<div class="map"><%= image_tag "http://maps.googleapis.com/maps/api/staticmap?center=#{#post.latitude},#{#post.longitude}&markers=#{#post.latitude},#{#post.longitude}&zoom=12&size=450x400&sensor=false&key=AIzaSyCKzKMEhSNgwSXf7WV71pHWgzdpMkPn8W4",
class: 'img-fluid img-rounded', alt: "#{#post} on the map"%>
</div>
post.rb
class Post < ApplicationRecord
belongs_to :user
geocoded_by :address
after_validation :geocode, if: ->(obj){ obj.address.present? and obj.address_changed? }
reverse_geocoded_by :latitude, :longitude
after_validation :reverse_geocode
has_many :rsvps
has_many :users, through: :rsvps
validates :name, presence: true
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
has_many :rsvps
has_many :posts, through: :rsvps
validates :email, presence: true
rsvp.rb
class Rsvp < ApplicationRecord
belongs_to :user
belongs_to :post
end
#rsvp migration
class Rsvp < ApplicationRecord
belongs_to :user
belongs_to :post
end
So I've looked around in Stackoverflow and googled for a bit but I'm at a loss. I would really appreciate an answer that would solve this issue. I just want the rsvp button to show users who havent rsvped for the specific post/event.
The most important thing to me is a database constraint. You want to instruct the database to throw an error in those cases.
In a migration
add_index :rsvps, [:user_id, :post_id], unique: true
And a validation that reflect that, just to make rails aware of this
validates :user_id, uniqueness: { scope: :post_id }
Now we're sure that no more than one pair some_user_id, some_post_id is present in the database.
Now, let's instruct the view to not display the button in those cases
<% unless Rsvp.exists?(post: #post, user: #post.user) %>
<div class="rsvp">
<%= button_to "Rsvp now", rsvps_post_path(#post), class: "btn btn-primary" %>
</div>
<% end %>
I'd move that exists query in the action and use just a boolean here, this is just demonstrative.
I have a problem : when a customer enters his shipping and billing informations in my form, the fields of the address model lose all information if the page is reloaded.
It works with the other fields, like email, that are included directly in the order model. How could I leave the fields filled after reloading ?
Here's my new.html.erb file :
<%= form_for #order do |f| %>
<ul>
<% #order.errors.each_with_index do |msg, i| %>
<li><%= msg[1] %></li>
<% end %>
</ul>
<%= f.text_field :email, placeholder: "email" %>
<%= f.fields_for :shipping_address_attributes do |sa| %>
<%= sa.text_field :first_name, placeholder: "Firstname" %>
<%= sa.text_field :last_name, placeholder: "Name", autocomplete: true %>
<%= sa.text_field :address1, placeholder: "Address", autocomplete: true %>
#etc.
<% end %>
<p><%= f.submit 'Next step' %></p>
<% end %>
My models :
class Order < ActiveRecord::Base
belongs_to :billing_address, :class_name => "Address"
belongs_to :shipping_address, :class_name => "Address"
accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address, reject_if: :bill_to_shipping_address
class Address < ActiveRecord::Base
belongs_to :user
has_many :billing_addresses, :class_name => "Order", :foreign_key => "billing_address_id", dependent: :nullify
has_many :shipping_addresses, :class_name => "Order", :foreign_key => "shipping_address_id", dependent: :nullify
validates_presence_of :first_name, :last_name, :address1, :city, :country, :phone, :postal
and my order_controller.rb:
def new
#user = current_user
#order_items = current_order.order_items
#order = current_order
#amount = #order.subtotal
end
def update
#order_items = current_order.order_items
#order = current_order
if #order.update(order_params)
redirect_to recapitulatif_de_la_commande_path
else
redirect_to(:back)
end
end
EDIT
Maybe the error is due to the fact that the order is not linked to any shipping address before the update action ? It works only if address model validate the presence of each attributes.
Any idea ?
I wanted to create twitter like followers and following thing.
in my view i have
<% if current_user.following?(#otheruser) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
in _follow.html.erb
<%= form_for (#otheruser), url: createfollower_path(#otheruser) ,:class=>"form-horizontal",method: :post do |f| %>
<%= f.hidden_field :user_id, :value => #otheruser.id %>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
in controller create action
def create
user = User.find(params[:user_id])
current_user.follow(user)
redirect_to followuser_url
end
in user.rb
has_many :followers, class_name: "Relationship" #-> users following you
has_many :following, class_name: "Relationship", foreign_key: :follower_id, foreign_key: :user_id
def follow(other_user)
relationships.create(user_id: other_user.id)
end
in relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :user
belongs_to :follower, class_name: "User"
validates :user, :follower, presence: true
validates :user_id, uniqueness: { scope: :follower_id }
end
now when I am trying to submit the follow button it is showing error as
"Couldn't find User with 'id'=" and parameters are
{"utf8"=>"✓","authenticity_token"=>"681q5ft03+WRdqgHagh/gI1mV3uohwaEj1sF8zdTycUAN5yTiVMT/wGCV4tLPRVRRFRA+6mYSS1bXk2ormA/zw==",
"user"=>{"user_id"=>"7"},
"commit"=>"Follow",
"format"=>"7"}
You need to rewrite your controller's create action.
def create
user = User.find(params[:user][:user_id])
current_user.follow(user)
redirect_to followuser_url
end
Should worked !!!
In my Rails app, I need to show user email id's with checkboxes in a form to allocate users to a particular project. I have an array object #programmers and each row in the object contains email id's which I need to show inside the form with checkboxes.
My partial view containing form is:
_allocate_programmer.html.erb
<h1> Allocate programmers </h1>(Please check the programmers that you want to add)<br />
<%= form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% unless #programmers.nil? %>
<% #programmers.each do |programmer| %>
<%= f.check_box :programmer, programmer.email %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My routes.rb has:
match 'projects/:id/allocate_programmers' => 'projects#allocate'
My projects_controller.rb has the following code:
def allocate
#project = Project.find(params[:id])
#programmers = User.where(:role => 'programmer')
render "_allocate_programmer"
end
I am getting following error in the view
NoMethodError in Projects#allocate
Showing /home/local/Rajesh/ticket_system/app/views/projects/_allocate_programmer.html.erb where line #18 raised:
undefined method 'merge' for "test#gmail.com":String
I think its an issue with checkbox hash. Please help.
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :token_authenticatable,
:rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :role
# attr_accessible :title, :body
has_many :assignments
has_many :projects, :through => :assignments
has_many :tickets
ROLES = ['admin', 'network/system admin', 'manager', 'programmer']
def role?(base_role)
ROLES.index(base_role.to_s) <= ROLES.index(role)
end
end
Project.rb
class Project < ActiveRecord::Base
attr_accessible :project_name, :description, :duration_from, :duration_upto, :user_id
has_many :assignments
has_many :users, :through => :assignments
validates :project_name, :presence => true
validates :description, :presence => true
validates :duration_from, :presence => true
validates :duration_upto, :presence => true
#validates :user_id, :presence => true //this gives error
end
Assignment.rb
class Assignment < ActiveRecord::Base
attr_accessible :user_id, :project_id
belongs_to :user
belongs_to :project
end
Please check. I have updated the question with 3 models.
Supposing that you have set up your associations correctly.
<% #programmers.each do |programmer| %>
<%= check_box_tag "project[programmer_ids][]", programmer.id, #project.programmers.include?(programmer) %>
<%= programmer.email %>
<% end %>
ref this
check_box does not work when the check box goes within an array-like parameter
Following should work for you
<% #programmers.each do |programmer| %>
<%= check_box_tag "project[programmer]", programmer.email %>
<% end %>
I have a Tag, User and Post model:
tag.rb:
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
end
tagging.rb:
class Tagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
(There is a many-to-many association between posts and tags)
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
has_many :posts, :dependent => :destroy
end
post.rb:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :tag_name
attr_accessor :tag_name
validates :title, :presence => true,
:length => { :maximum => 30 },
:uniqueness => true
validates :content, :presence => true,
:uniqueness => true
belongs_to :user
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
attr_writer :tag_names
after_save :assign_tags
def tag_names
#tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
if #tag_names
self.tags = #tag_names.split(" ").map do |name|
Tag.find_or_create_by_name(name)
end
end
end
end
Right now, the currently logged user (via Devise) see all the posts:
posts_controller.rb:
class PostsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
autocomplete :tag, :name
def index
#title = "Posts"
#posts = Post.paginate(:page => params[:page], :per_page => 5)
end
views/posts/index.html.erb:
<div id="mainbar" class="nine columns">
<% #posts.each do |post| %>
<div id="post-<%= post.id %>" class="post">
<h3><%= link_to post.title, post %></h3>
<div class="post_content">
<p><%= post.content %></p>
</div>
<%= will_paginate #posts %>
I want to enable users to follow/subscribe tags so they only see posts with these tags in the index page.
How would be the Model and migration to accomplish this?
EDIT:
Everything works fine now but I get this error when I enter the index page:
ActionView::Template::Error (undefined method `id' for []:ActiveRecord::Relation):
2: <h2><%= #title %></h2>
3:
4: <% #posts.each do |post| %>
5: <div id="post-<%= post.id %>" class="post">
6: <h3><%= link_to post.title, post %></h3>
7:
8: <div class="post-meta">
app/views/posts/index.html.erb:5:in `block in _app_views_posts_index_html_erb__75789648_88240890'
app/views/posts/index.html.erb:4:in `each'
app/views/posts/index.html.erb:4:in `_app_views_posts_index_html_erb__75789648_88240890'
the index view for posts:
<div id="mainbar" class="nine columns">
<h2><%= #title %></h2>
<% #posts.each do |post| %>
<div id="post-<%= post.id %>" class="post">
<h3><%= link_to post.title, post %></h3>
<div class="post-meta">
<span><%= link_to post.user.username, post.user %></span>
<span>Created At: <%= post.created_at %></span>
</div>
<div class="post-content">
<p><%= post.content %></p>
</div>
<p>Votes: <%= post.total_votes %></p>
<p>Comments: <%= post.comments_count %></p>
<ul>
<li><%= link_to 'Show', post %></li>
<li><%= link_to 'Edit', edit_post_path(post) %></li>
<li><%= link_to 'Destroy', post, confirm: 'Are you sure?', method: :delete %></li>
</ul>
<br />
</div>
<% end %>
<%= will_paginate #posts %>
<p><%= link_to 'New post', new_post_path, :class => 'sunset-orange button radius' %></p>
</div>
<div id="sidebar" class="three column">
<%= render 'layouts/sidebar' %>
</div>
Since a user can subscribe to many tags and a tag can be subscribed by many users, you will need to associate User and Tag by has_many association ( either through has_and_belongs_to_many or has_many :through similar to Tag and Post models' association).
class User < ActiveRecord::Base
has_many :subscriptions
has_many :subscribed_tags, :source => :tag, :through => :subscriptions
class Tag < ActiveRecord::Base
has_many :subscriptions
has_many :subscribed_users, :source => :user, :through => :subscriptions
class Subscription < ActiveRecord::Base
belongs_to :tag
belongs_to :user
Then in PostsController, select all posts with tags that the user has subscribed to.
def index
#posts = current_user.subscribed_tags.map(&:posts).flatten.paginate(:page => params[:page], :per_page => 5)
end
If you are using Will Paginate for pagination, you might get an undefined method 'paginate' for Arrays error, since using map will result in an array. So, you might need to add require 'will_paginate/array' to the corresponding controller.