I am using Paperclip, and my only problem is that in my image tag, I have an undefined method "image".
<%= image_tag #posts.image.url(:medium) %>
is where my error is occurring. When I loaded a new migration, I accidentally did "rails g paperclip user image" instead of "rails g paperclip posts image" so I went into my code and changed "user" to "posts." I asked something similar and someone mentioned that it was with my schema.rb file(?).
Just to be safe, this is my post controller:
class PostsController < ApplicationController
def index
#posts = Post.all.order('created_at DESC')
end
def new
#post = Post.new
if #post.save
redirect_to #post
else
render 'new'
end
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:title, :body, :image)
end
end
but here is my migration file:
class AddAttachmentImageToUsers < ActiveRecord::Migration
def self.up
change_table :posts do |t|
t.attachment :image
end
end
def self.down
remove_attachment :posts, :image
end
end
and my user.rb file:
has_attached_file :image, :styles => { large: '600x600>', medium: '300x300>', thumb: '150x150#' }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
From the comments and your code, it looks like your #posts variable is either empty or undefined. To add to the original answer, here's what I'd do:
#app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def index
#posts = Post.all.order(created_at: :desc)
end
end
#app/views/posts/index.html.erb
<% if #posts.any? %>
<% #posts.each do |post| %>
<%= image_tag post.image.url(:medium) %>
<% end %>
<% end %>
You must have the #posts variable referenced in the view which corresponds to the action you're running. From seeing your comments, it appears this might not be the case.
You need to be referencing single instances of the Post model, in order to have the image method available.
If it is not available, it either means you don't have the #posts variable declared properly, or your Paperclip gem is not set up properly.
this is my user.rb file
haha okay. THIS is the problem.
Make sure you put this in your post.rb file:
#app/models/post.rb
class Post < ActiveRecord::Base
has_attached_file :image, :styles => { large: '600x600>', medium: '300x300>', thumb: '150x150#' }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
Paperclip basically links stored images to database records. Thus, in order to append the image method to your model, you have to have the Paperclip options appended to it.
Putting the paperclip calls in user.rb will add the image method to your User model. You need to put those lines in the Post model.
BTW I met the guys who made Paperclip:
that it was with my schema.rb file(?).
The schema.rb file is located in /config/db/schema.rb.
Essentially, each time you migrate to your DB, the schema is updated, so that in the event you need to repopulate the db, Rails will be able to pull a pre-built set of SQL calls to do it.
Indeed, it is recommended that you use rake db:schema:load to
rebuild a database (rather than rake db:migrate). HOWEVER (VERY
IMPORTANT), IT DELETES ANY DATA in that database, making it
unadvisable to use it for anything other than building new db's.
You can read about Schema.rb here.
In regards to what your friend was saying, if you go into your schema.rb file, you'll be able to see which table has the paperclip columns added to it. By generating the migration for the users table, you may have caused a conflict.
You need to access image for one post at a time so you need to traverse the posts collection and fetch image for each post like this
<% #posts.each do |post| %>
<%= image_tag post.image.url(:medium) %>
<% end %>
I think the problem might be how you changing "user" to "posts.".it would be okay to just change controller or view name,but change model is a different thing that you have to generate a migration to change table name
Related
i followed a Youtube Video to implement ActiveAdmin Theme in my Rails App,- and everything worked like a charm (i thought).
https://www.youtube.com/watch?v=i2x995hm8r8
I followed every Step he took and i am a little confused right now because i can't create posts.
Whenever i try to create a New Post and type in the tile, body and select a image- it just won't do anything. It doesn't even give me a Error Message.
posts_controller.rb
class PostController < ApplicationController
def index
#post = Post.all.order('created_at DESC')
end
def create
#post = Post.new(params[:post].permit(:title, :body))
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
#post = Post.order("created_at DESC").limit(4).offset(1)
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
ActiveAdmin.register Post do
posts.rb
permit_params :title, :body, :image
show do |t|
attributes_table do
row :title
row :body
row :image do
post.image? ? image_tag(post.image.url, height: '100') : content_tag(:span, "No image yet")
end
end
end
form :html => {:multipart => true} do |f|
f.inputs do
f.input :title
f.input :body
f.input :image, hint: f.post.image? ? image_tag(post.image.url, height: '100') : content_tag(:span, "Upload JPG/PNG/GIF image")
end
f.actions
end
end
post.rb
class Post < ApplicationRecord
belongs_to :user
validates :title, presence: true, length: {minimum: 5}
validates :body, presence: true, length: { maximum: 140}
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
EDIT I:
Started POST "/admin/posts" for 127.0.0.1 at 2018-03-20 14:30:24 +0100
Processing by Admin::PostsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"f+hfBD3lzgXEfz1q38/i3YciHsbb5LYWbbHUUsyIeOCaNSUReUUVVTBE//Dw0zXxSuFCzcMfYuUGDtIJlNb58w==", "post"=>{"title"=>"asdasdasd", "body"=>"asdasdasd"}, "commit"=>"Create Post"}
AdminUser Load (0.3ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = $1 ORDER BY "admin_users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Rendering /Users/useruser/.rvm/gems/ruby-2.4.2/bundler/gems/activeadmin-2cf85fb03ab3/app/views/active_admin/resource/new.html.arb
Rendered /Users/useruser/.rvm/gems/ruby-2.4.2/bundler/gems/activeadmin-2cf85fb03ab3/app/views/active_admin/resource/new.html.arb (134.6ms)
Completed 200 OK in 230ms (Views: 148.3ms | ActiveRecord: 5.7ms)
If you need more of my Code just tell me what i should post in here.
I am just getting started with Ruby on Rails and Programming overall, so yes indeed, i am a Newb.
Thanks in advance!
From what I see in your edit 1, I see that you render new after submiting form. It means that your Post is not being saved. It also means that your application does exactly what it should do.
I assume that you are using latests Rails 5.
In Post model, you have belongs_to association (Post belongs to User).
In Rails 5, that means user or user_id has to be provided, to create Post (Post cannot belong to noone), else you won't be able to save.
Depending how you created association in table, you might be able to pass user or user_id in params.
Another way to create post belonging to particular user is:
#user = User.first
#post = #user.posts.build(post_params)
For ActiveAdmin, you can use default form that is created based on your model.
Just make sure you permit all params when creating it that way
ActiveAdmin.register Post do
permit_params %i[title body image user_id]
...
end
You can also set belongs_to :user association as optional.
Now some general advices from me:
First of all use proper indentation.
My advice to you is install Rubocop gem.
Second:
def show
#post = Post.find(params[:id])
#post = Post.order("created_at DESC").limit(4).offset(1)
end
That doesn't make much sense, you overwrite instance variable just after first assignment.
#post = Post.order("created_at DESC").limit(4).offset(1) is more of an index action, since it does not show particular posts, it show 2..5 newest posts.
def post_params
params.require(:post).permit(:title, :body)
end
Misses image attribute.
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :body))
redirect_to #post
else
render 'edit'
end
end
You duplicate params[:post].permit(:title, :body). You hgave already created private method for that. Use it here. Same goes for creation action, you duplicated it there too. Read what DRY code is about (google it).
You have belongs_to :user but never set a user_id. A belongs_to relation is by default required (in recent rails 4/5), and this will block the saving. The easiest way, for now, to fix this is to write it as following
belongs_to :user, optional: true
[EDIT: how to store current-user as owner of post]
If you want to automatically set the user to the currently logged in user, which I think is the intention, you can add the following to your active-admin configuration:
ActiveAdmin.register Post do
# .. keep your original configuration here ...
before_build do |record|
record.user = current_user
end
end
Or add an extra field to the form allowing the administrator to select the user?
I am trying to create a simple blog application. In which each post can be associated with the tags. This is my view
_form.hmtl.erb
<%= form.collection_select(:tag_ids, #tags, :id, :name, {}, :multiple => true) %>
This is my controller
posts_controller.rb
def new
#post = #topic.posts.new
#tag = #post.tags.new
#tags = Tag.all
end
def create
#post = #topic.posts.new(post_params)
if #post.save
redirect_to topic_posts_path
else
render 'new'
end
end
def post_params
params.require(:post).permit(:title,:content,:post_image, tag_ids: [])
end
end
Model Post.rb
has_and_belongs_to_many :tags
I am getting an error while creating new post "NoMethodError in Posts#create", "undefined method `map' for nil:NilClass". I am not able to find where the error is.
You should have a join table with name posts_tags.rb
class Post_Tag < ApplicationRecord
belongs_to :tag
belongs_to :post
end
so you have already some tags which you want to be selected with post and join table should be updated with post_id and tag_id
change this in your form_partial: -
<%= select_tag "tag_ids", options_for_select(#tags,:id,:name),{}, multiple: true%> <br/><br/>
Note: - you should not use form.collection_select(:tag_ids...) Reason being form_for is used here for #post object and tag_ids is not attribute of #post object.
so on submitting form you should get array of tag's ids in params[:tag_ids]
def create
#post = #topic.posts.new(post_params)
if #post.save
#create join table for tags that are associated with post
#post.tags << Tag.find(params[:tag_ids])
redirect_to topic_posts_path
else
render 'new'
end
end
so here you can get
#post.tags => which will return you collection of tags associated with the post
if you are using this scenario you have to make MANY TO MANY relation between these two models.
has_and_belongs_to_many :tags
then in form you should use like
form.collection_select(:post, :tag_id, Tag.all, :id, :name_with_initial, prompt: true)
The #tags variable is missing from your create action in controller - you have declared it in new, but not in create. It may cause error in view if save was unsucessful and action tries to re-render the form.
Not sure if that's all, because I'm not sure where the error is thrown exactly. But as you said in one of the comments - it works when you use Tag.all instead of #tags.
I'm using friendly_id 5.1.0, and when I try to update an entry, for exemple creating a new Article, instead of updating the data of the entry, it creates a new one.
I have slugged the title and when I don't change it when editing an article, it creates a slug with a bunch of numbers/letters :
http://localhost:3000/articles/first-article-2d392b8e-92b8-44b0-ad67-50dd674f7aaa
Here's my article.rb Model :
class Article < ActiveRecord::Base
extend FriendlyId
has_many :comments
friendly_id :title, :use => :slugged
validates :title, presence: true,
length: { minimum: 5}
def should_generate_new_friendly_id?
new_record? || title_changed?
end
when I add :use => [:slugged, :history], when I update an entry and keep the same title, it can't save it because my :slug field is unique :true.
Here's my articles_controller.rb :
class ArticlesController < ApplicationController
def index
#articles = Article.all.order(created_at: :desc)
end
def show
#article = Article.friendly.find(params[:id])
if request.path != article_path(#article)
redirect_to #article, status: :moved_permanently
end
end
def new
#article = Article.new
end
def edit
#article = Article.friendly.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.friendly.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.friendly.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
Here's my GitHub repository whith my (unfinished) project : https://github.com/TheDoctor314/blog
This issue has nothing to do with FriendlyID.
Your problem is here (a form used on both new and edit):
<%= bootstrap_form_for :article, url: articles_path do |f| %>
It does not attempt to use your #article object to built that form. So your form always issues a POST request to articles_path, which results in create every time. What you should do instead is:
<%= bootstrap_form_for #article do |f| %>
That way form builder will check if that object is persisted? already, and if so, generate a form that issues a PATCH request to that specific article that triggers an update action. It will try to guess the URL by itself. And it will succeeed only if you follow conventions tightly enough.
If #article is not persisted?, it will do what it did: make a POST to articles_path.
Permit id in params
params.require(:article).permit(:id, :title, :text)
Hope that helps!
The Edit form is routing to create action for articles controller instead of update action. You need to change your form path, when editing the files.
If you see the articles index action, you can see new articles are being added, instead of updating
So I am making a site where users can only submit a post once, and then the "new post" button goes away forever.
I would also like to put a limit on the overall amount of posts. So, only the first 100 or so people can actually post.
I used rails generate scaffold to build the posting system.
I don't know where to start.
Thanks!
You can either create a constant if all user will have the same limit, or add a field in your user record if you plan for each user to have different limits.
Then you create a validator which check the number of existing posts and forbid creation of new posts if the limit is reached
More info in rails guide: http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
An alternative approach is using a policy object. Here's how I would approach this using Pundit.
Updated:
app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
def self.limit_exceeded?(max = 100)
count >= max
end
end
app/models/user.rb
class User < ActiveRecord::Base
has_one :post
end
app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def create?
!user_has_post? && space_to_post?
end
private
def user_has_post?
user.post.present?
end
def space_to_post?
!Post.limit_exceeded?
end
end
app/controllers/posts_controller.rb
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
authorize(:post)
#post = current_user.build_post(post_params)
if #post.save
redirect_to #post, notice: "Your post was created!"
else
render :new
end
end
private
def post_params
params.require(:post).permit(:message)
end
end
app/view/posts/new.html.erb
<% if policy(:post).create? %>
<%= form_for(#post) do |form| %>
<%= form.text_area :message %>
<%= form.submit "Post" %>
<% end %>
<% else %>
You cannot post.
<% end %>
This code assumes the user is authenticated. If you haven't incorporated authentication, you'll need to use a gem for that, or roll your own implementation. I'd recommend Devise or Clearance.
Good luck!
I'm a new rails developer who has a basic scaffolded crud application that I modified a bit.
I'm getting this error:
undefined method description for #<ActiveRecord::Relation:0x00000102df26d8>
when I visit john/recipes/46. Here's my view:
<h1 itemprop="name"><%= #recipe.name %></h1>
<ul>
<li><%= link_to 'Edit', edit_recipe_path(#recipe) %></li>
</ul>
<p itemprop="description"><%= #recipe.description %></p>
here's my routes:
match "/:username" => "recipes#index"
scope ':username' do
resources :recipes
end
here's my show index:
def show
#user = User.find_by_username params[:username]
#recipe = Recipe.where(:user_recipe_id => params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #recipe }
end
end
and my model:
before_save :set_next_user_recipe_id
belongs_to :users
validates :user_recipe_id, :uniqueness => {:scope => :user_id}
def to_param
self.user_recipe_id.to_s
end
def set_next_user_recipe_id
self.user_recipe_id ||= get_new_user_recipe_id
end
def get_new_user_recipe_id
user = self.user
max = user.recipes.maximum('user_recipe_id') || 0
max + 1
end
attr_accessible :description, :duration, :author, :url, :name, :yield, :ingredients_attributes, :user_recipe_id, :directions_attributes, :tag_list, :image
The reason I'm doing a Recipe.where(:user_recipe_id => params[:id]) instead of Recipe.where(:id => params[:id]) is because I'm trying to get so instead of john/recipes/46 showing the 46th recipe in the database, instead to show the 46th recipe that belongs to John.
Thanks for all help!
You're only trying to look for one recipe, but your query is searching for multiples. When you use a plain where(...) without ending it with .first, Rails interprets it as "show me all (multiple) Recipes with this user id" instead of "show me the (one) recipe with this id".
So you need to either put .first at the end of your query:
#recipe = Recipe.where(:user_recipe_id => params[:id]).first
or use an ActiveRecord finder that only returns one record:
#recipe = Recipe.find_by_user_recipe_id(params[:id])