I have a blog that use devise for authentication and where user can create posts, I have created a basic dashboard where users will be able to manage their posts
this is my dashboard controller
before_action :authenticate_user!
def index
#posts = Post.find(:all, :conditions => [ "user_id = ?", #current_user ])
end
this my dashboard view
<% #posts.each do |post| %>
<%= post.content %>
<% end %>
this my user model
has_many :posts
and my post model
belongs_to :user
this is my schema.rb
create_table "posts", force: true do |t|
t.text "content"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
but when i go to the dashboard i am not getting any of my post and when i change my dashboard controller to
def index
#posts = Post.all
end
I'am getting all the posts so can someone tell me where is my fault
The find(:all, :conditions => []) was deprecated in Rails 3.2. Instead try:
def index
#posts = Post.where(:user_id => current_user)
end
Also, make sure you are adding a user_id in the create method in your controller:
def create
#post = post.new(post_params)
#post.user_id = current_user
REST OF CODE GOES HERE
end
Replace
#posts = Post.find(:all, :conditions => [ "user_id = ?", #current_user ])
with
#posts = #current_user.posts
Related
I created a post_category table to add a category to specifics posts.
For example I created post_categories as Countries, Like Japan or China. And I want to create post which are come from culture or mode from countries like Japan or China. I focused only on post_categories as countries for now and below is the code I did.
I created this PostCategory, here are the migration and model
create_table "post_categories", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
class PostCategory < ActiveRecord::Base
has_many :posts, dependent: :destroy
NAMES = ["Japon", "Chine", "Corée du Sud", "Moyen Orient", "Indien"]
validates :name, inclusion: { in: PostCategory::NAMES, allow_nil: false }
end
And I created a Post with the PostCategory foreign key, here are the migration and model
create_table "posts", force: :cascade do |t|
t.string "cover"
t.string "subtitle"
t.string "title"
t.text "introduction"
t.text "body"
t.text "conclusion"
t.string "tag"
t.string "source"
t.string "link"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_category_id"
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :post_category, dependent: :destroy
TAGS = ["Design", "Mode", "Tendance", "Life-Style", "Tradition", "Gastronomie", "Insolite", "Technologie"]
validates :tag, inclusion: { in: Post::TAGS, allow_nil: false }
mount_uploader :cover, ImageUploader
end
I want to create a category with a simple form collection and I want i will be displayed on the post show#view
Here is the post_categories controller
class PostCategoriesController < ApplicationController
# before_action :set_post_category, only: [:show, :new, :create, :destroy]
def show
#post_category = PostCategory.find(params[:id])
end
def index
#post_categories = PostCategory.all
end
def create
#post_category = post_categories.new(post_category_params)
if #post_category.save
redirect_to #post
else
render 'post_categories/show'
end
end
def new
#post_category = PostCategory.new
end
def edit
end
def update
end
def destroy
#post_category = PostCategory.find(params[:id])
#post_category.destroy
redirect_to post_path(#post)
end
private
# def set_post
# #post = Post.find(params[:post_id])
# end
def find_post_category
#post_category = PostCategory.find(params[:id])
end
def post_category_params
params.require(:post_category).permit(:name, :description)
end
end
And here is the posts controller
class PostsController < ApplicationController
before_filter :authenticate_user!, except: [:index, :show]
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
# #alert_message = "Vous lisez #{#post.title}"
end
def new
# if current_user and current_user.admin?
#post = Post.new
# else
# redirect_to posts_path
# end
end
def create
# if current_user and current_user.admin?
#post = #post_category.posts.new(post_params)
##post = current_user.posts.new(post_params)
if #post.save
redirect_to #post
else
render :new
end
# else
# render 'shared/404.html.erb'
# end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render :edit
end
end
def destroy
#post.destroy
redirect_to :back
end
private
# def find_post
# #post = Post.find(params[:id])
# end
def set_post_category
#post_category = PostCategory.find(params[:post_category_id])
end
def post_params
params.require(:post).permit(:title, :subtitle, :introduction, :body, :cover, :tag, :post_category_id)
end
end
I don't know what views could I do create and how calling the post new#view because I configured my routes like that, and I need a post_category_id.
resources :post_categories do
resources :posts
end
That's I have to use this following path
post_category_posts GET /post_categories/:post_category_id/posts(.:format) posts#index
POST /post_categories/:post_category_id/posts(.:format) posts#create
new_post_category_post GET /post_categories/:post_category_id/posts/new(.:format) posts#new
edit_post_category_post GET /post_categories/:post_category_id/posts/:id/edit(.:format) posts#edit
post_category_post GET /post_categories/:post_category_id/posts/:id(.:format) posts#show
PATCH /post_categories/:post_category_id/posts/:id(.:format) posts#update
PUT /post_categories/:post_category_id/posts/:id(.:format) posts#update
DELETE /post_categories/:post_category_id/posts/:id(.:format) posts#destroy
post_categories GET /post_categories(.:format) post_categories#index
POST /post_categories(.:format) post_categories#create
new_post_category GET /post_categories/new(.:format) post_categories#new
edit_post_category GET /post_categories/:id/edit(.:format) post_categories#edit
post_category GET /post_categories/:id(.:format) post_categories#show
PATCH /post_categories/:id(.:format) post_categories#update
PUT /post_categories/:id(.:format) post_categories#update
DELETE /post_categories/:id(.:format) post_categories#destroy
I want to add the category on my show#view post and create a multisearch access to find posts added to a specific category. Thank you for your help
The way you have setup your relations since has a very big flaw - a post can only belong to a single category since the id is stored on the posts table.
Instead you would commonly use a many to many relationship:
class Post < ActiveRecord::Base
has_many :categories, :categories
has_many :post_categories
end
class Category < ActiveRecord::Base
has_many :posts
has_many :posts, through: :categories
end
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
validates_uniqueness_of :category_id, scope: :post_id
end
Here the categorizations table acts as a join table which links Post and Category - A post can have any number of categories and vice versa.
ADDED:
To create the join model and a migration to create table you would do:
rails g model Categorization post:belongs_to category:belongs_to
Using belongs to in the generator by default creates foreign keys for post_id and category_id.
You might want to add a compound uniqueness constraint in the migration as well.
def change
# ...
add_index(:categorizations, [:post_id, :category_id], unique: true)
end
Your on the right track with your CategoriesController but I would not use a nested route to create posts. Instead you might want to just use a plain old rails controller and let the user select categories via check boxes:
<%= form_for(#post) do |f| %>
<%= f.collection_check_boxes :category_ids, Category.all, :id, : name %>
<% end %>
You would then add the category_ids param to the whitelist:
def post_params
params.require(:post)
.permit(:title, :subtitle, :introduction,
:body, :cover, :tag, category_ids: []
)
end
The weird category_ids: [] syntax is because we want to allow an array of scalar values.
Querying for posts from a category by id can be done like so:
Post.joins(:categories).where(category: 1)
You can even select multiple categories by passing an array:
Post.joins(:categories).where(category: [1, 2, 3])
To hook this together from the view you would use a link (for a single category) or a form (yes forms can be used for GET) with checkboxes or selects.
Dealing with textual input is a bit trickier. A naive implementation would be:
Post.joins(:categories).where(category: { name: params[:search_query] })
However the user input would have to match exactly. There are several gems that provide search features to active record. However I would wait with the feature until you have a bit more experience as it can be tricky to implement.
See:
Rails guides: The has_many :through Association
Rails guides: Strong Parameters
Rails api: collection_check_boxes
Ive been trying to build an messaging system for my site which uses devise for authentication. The functionality it requires is to be able to send a message to either one or more recipients (preferably with a checklist form listing users as well). After searching for a while I found a couple gems such as mailboxer, but I didn't need all its features and wanted to build my own system for sake of learning (still a newbie at rails).
I have followed this ancient tutorial ( http://web.archive.org/web/20100823114059/http://www.novawave.net/public/rails_messaging_tutorial.html ). I realize this is a very old tutorial but it is the only one I could find which matched what I was trying to achieve.
I have followed the tutorial to a T and even copied and pasted the code from the tutorial after my code didn't work.
when trying to access http://localhost:3000/mailbox i get a NoMethodError in MailboxController#index
undefined method `messages' for nil:NilClass
app/controllers/mailbox_controller.rb:12:in `show'
app/controllers/mailbox_controller.rb:6:in `index'
I have also referenced this question Rails 3: undefined method messages for Folder which had the same error as me but the topic just seemed to go no where.
mailbox_controller.rb
class MailboxController < ApplicationController
def index
#folder = current_user.inbox
show
render :action => "show"
end
def show
#folder ||= current_user.folders.find_by(params[:id])
#messages = #folder.messages :include => :message, :order => "messages.created_at DESC"
end
end
models/folder.rb
class Folder < ActiveRecord::Base
acts_as_tree
belongs_to :user
has_many :messages, :class_name => "MessageCopy"
end
Any help with this would be awesome, also just let me know if you need any more info and will post it.
I ended up figuring out the messaging system with a few modifications. I wanted to post my whole solution since it gave me a difficult time and might be useful to others. I kept it very simple and did not include the the folder model which was giving me the problem in the first place, but none the less it is functioning.
Heres are my associations
model/message.rb
attr_reader :user_tokens
belongs_to :sender, :class_name => 'User'
has_many :recipients
has_many :users, :through => :recipients
def user_tokens=(ids)
self.user_ids = ids
end
model/recipient.rb
belongs_to :message
belongs_to :user
model/user.rb
has_many :messages, :foreign_key => :sender_id
This is my messages controller
messages_controller.rb
def new
#message = Message.new
#user = current_user.following
#users = User.all
# #friends = User.pluck(:name, :id).sort
end
def create
#message = current_user.messages.build(message_params)
if #message.save
flash[:success] = "Message Sent!"
redirect_to messages_path
else
flash[:notice] = "Oops!"
render 'new'
end
end
def index
#user = User.find(current_user)
#messages = Recipient.where(:user_id => #user).order("created_at DESC")
end
private
def message_params
params.require(:message).permit(:body, :sender_id, user_tokens: [])
end
My Views
_form.html.erb
</div>
<!-- displays the current users frinds their following -->
<%= f.select :user_tokens, #user.collect {|x| [x.name, x.id]}, {}, :multiple => true, class: "form-control" %>
<br>
<div class="modal-footer">
<%= f.button :submit, class: "btn btn-primary" %>
</div>
Schema
messages_table
t.text "body"
t.integer "sender_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "body_html"
recipients_table
t.integer "message_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
I hope this helps.
I have an Order and an OrderTransactions model in my Rails4 application. They have a basic has_one and belongs_to relationship between them.
I'm posting requests from /orders/new page to the bank's URL as you can see below:
<%= simple_form_for(#order, :url => "https://testsanalpos.est.com.tr/servlet/est3Dgate", :method => :post) do |f| %>
<% #hashing.each do |k, v| %>
<%= f.input k, input_html: {name: k, value: v}, as: :hidden %>
<% end %>
<%= f.input :participation_id, ... %>
<%= f.button :submit, "Ödeme Yap" %>
<% end %>
The #hashing, hash is coming from my controller =>
class OrdersController < ApplicationController
before_filter :authenticate_user!
before_action :set_order, only: [:show, :edit, :update, :destroy]
skip_before_action :verify_authenticity_token
def new
#order = Order.new
#hashing = {
clientid: POS['clientid'],
oid: Time.now.to_i.to_s,
amount: POS['amount'],
okUrl: POS['okUrl'],
failUrl: POS['failUrl'],
rnd: Time.now.to_i.to_s,
}
end
def create
#order = Order.new(order_params)
respond_to do |format|
#order.purchase
end
end
def success
end
def fail
end
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:id, :ip_address, :first_name, :last_name, :card_brand, :card_number, :card_verification, :card_expires_on, :user_id, :participation_id)
end
end
Order.rb =>
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :participation
has_one :transaction, :class_name => "OrderTransaction"
def purchase
participation.update_attribute(:payment_status, true)
create_transaction(:action => "purchase", :response => response)
end
end
The bank's page is getting all necessary information from the user like credit card number, card expiration date etc. My application is not doing anything about purchase process, all of them are happening on the bank's side.
Then the bank is returning me a bunch of parameters about payment process. If the payment is success full, bank is posting the parameters to my /orders/success.html.erb and if it fails it is posting to /order/fail.html.erb.
I have 2 problems =>
1) I want the Order model instance is created whatever the response is successful or failed. It seems like that should be happening by create method in controller but it not working :/
2) How can I get the parameters that the bank send to my /fail or /success URL? I need to get them into my application and save them as a OrderTransaction instance in my database. I can see the parameters in my logs like this =>
Started POST "/orders/fail" for 127.0.0.1 at 2014-06-01 13:40:28 +0300
Processing by OrdersController#fail as HTML
Parameters:
{
"TRANID"=>"",
"Faturafirma"=>"OMÜ Uzaktan Eğitim Merkezi",
"islemtipi"=>"Auth",
"refreshtime"=>"5",
"lang"=>"tr",
"amount"=>"30",
"ACQBIN"=>"490740",
"clientIp"=>"193.140.28.145",
"name"=>"AKBANK",
"cardHolderName"=>"dsadas dasdsa",
"okUrl"=>"http://localhost:3000/orders/success",
"storetype"=>"3d_pay_hosting",
"Response"=>"Declined"
....
}
DB Schema =>
create_table "orders", force: true do |t|
t.integer "participation_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "order_transactions", force: true do |t|
t.integer "order_id"
t.string "clientip"
t.string "cardholdername"
t.string "response"
t.string "errmsg"
...
t.datetime "created_at"
t.datetime "updated_at"
end
Routes.rb =>
...
post 'orders/success' => 'orders#success'
post 'orders/fail' => 'orders#fail'
resources :orders, only: [:index, :new, :create]
...
Suggest:
Move your creation success failure into a model and pass it such.
def success
Order.create_from_params(order_params)
end
def fail
Order.create_from_params(order_params)
end
Then handle success failure from params using response Decline etc..
class Order<ActivewRecord::Base
def self.create_from_params(order_params)
self.create(inflatewithfields) && self.purchase if params[response'] == 'success'
self.create(inflatewithfields) if params[response'] == 'Decline'
end
end
I have an index page that hides/shows different Authors by using a boolean. The problem that I am having is that signed in users can still access hidden authors and their books through the URL.
How can I prevent current users from navigating to hidden Authors and their corresponding Books through the URL? Is there a way to redirect them back to Authors Page if author is hidden?
Currently, I have used the Controllers & a boolean value to help hide/show Authors or Books from signed in users. Can someone please point me in the right direction. Here is my Code.
MODELS
class Author < ActiveRecord::Base
attr_accessible :name, :photo
has_many :books
end
class Book < ActiveRecord::Base
attr_accessible :author_id, :title, :photo
belongs_to :author
end
CONTROLLERS
class AuthorsController < ApplicationController
before_filter :signed_in_user, only: [:index]
before_filter :admin_user, only: [:edit, :update, :destroy, :new, :show]
respond_to :html, :js
###Only displays unhidden authors to non admin users.
def index
if current_user.admin?
#authors = Author.all(:order => "created_at")
else
#authors = Author.where(:display => true).all(:order => "created_at")
end
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to (root_path), notice: "Please sign in."
end
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
class BooksController < ApplicationController
before_filter :signed_in_user, only: [:index]
before_filter :admin_user, only: [:edit, :update, :destroy, :new, :show]
before_filter :get_author
respond_to :html, :js
def get_author
#author = Author.find(params[:author_id])
end
def index
#books = #author.books
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to (root_path), notice: "Please sign in."
end
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
VIEWS
Authors index.html.erb
<% #authors.each do |author| %>
<%= link_to (image_tag author.photo(:medium)),
url_for(author_books_path(author)),
class: "img-rounded" %>
<% end %>
### How Can I prevent Users from accessing Hidden Author's Books (Index Page)
Books index.html.erb
<% #books.each do |book| %>
<%= image_tag book.photo(:medium) %>
<%= book.name %>
<% end %>
ROUTES
resources :authors do
resources :books
end
SCHEMA
create_table "authors", :force => true do |t|
t.string "name"
t.boolean "display", :default => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.datetime "photo_updated_at"
end
create_table "books", :force => true do |t|
t.integer "author_id"
t.string "title"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.datetime "photo_updated_at"
end
Use a proper authorization model, such as CanCan.
The key part (for CanCan) would be in authorizing based on user roles:
if user.role == admin
can :manage, :all
else
can :read, Author, display: true
end
There is a helpful RailsCast to step you through using CanCan for authorization.
Other options exist, such as Declarative Authorization, or you can roll your own.
Use a proper authorization model, such as CanCan.
Personally, I'm not sure I agree with this, at least given the scope of the issue you seem to be trying to solve. However, your comments in /app/views/books/index.html.erb seem to indicate you wanted to place some logic in your view file. Do NOT do this. Following proper MVC architecture, what you're attempting to do falls under the category of business logic. As such, the code that controls this should be in your controllers.
In your /app/controllers/book_controller.rb file, change the action for an Author's books page to redirect back to the author depending on the author's attributes. Something like this: (not sure what the exact path would be):
def index
# Redirect if author is set to hidden
if !#author.display
redirect_to author_path
else
#books = #author.books
end
end
in the Authors#show Controller, you can write for example --
Authors#Show
def show
#author = Author.find(params[:id])
redirect_to root_url unless #author.display
end
In this case, when a user visits any author's url, it will check to see if that author's display attribute is true or not, and redirect accordingly.
I am really hoping to get this resolved tonight so any help would be great.
I added this class method into my post.rb model
def self.without_review
where(review: false)
end
What I am trying to do is ONLY show all posts on the site where review=false. If review=true, I want to manually approve them before they're displayed. Right now, all posts are getting displayed whether the review is true or false.
Here's my post controller
class PostsController < ApplicationController
before_filter :signed_in_user
before_filter :load_post, only: :destroy
def create
#post = current_user.posts.build(params[:post])
if #post.save
flash[:success] = "Shared!"
redirect_to root_path
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def correct_user
#post = current_user.posts.find_by_id(params[:id])
redirect_to root_path if #post.nil?
end
def load_post
#post = current_user.admin? ? Post.find(params[:id]) : current_user.posts.find(params[:id])
end
end
and here's the full post.rb model
class Post < ActiveRecord::Base
attr_accessible :content, :review
belongs_to :user
validates :user_id, presence: true
validates :content, presence: true
default_scope order: 'posts.created_at DESC'
def self.without_review
where(review: false)
end
end
The schema of the posts table to show how "review" is set up (last row)
create_table "posts", :force => true do |t|
t.text "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "review", :default => false
The Static Pages Controller
class StaticPagesController < ApplicationController
def home
if signed_in?
#post = current_user.posts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
def post1
if signed_in?
#post = current_user.posts.build
end
end
end
UsersController (def show)
def show
#user = User.find(params[:id])
#posts = #user.posts.paginate page: params[:page], :per_page => 15
end
You didn't show the controller/action where the actual listing of posts is generated, but I guess you have to replace Post.all with Post.without_review there.