Associations between two models [closed] - ruby-on-rails

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Thank you for visiting. I'm currently building a blogging app which will have 3 models. User, Article and Comments that will go into comments. I hope someone can help explain to me where I'm going wrong and how I can associated models better. Current error I get is undefined method `users' in Articles#new controller.
My current code is:
Schema
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "body"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", force: :cascade do |t|
t.text "body"
t.integer "post_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["post_id"], name: "index_comments_on_post_id"
t.index ["user_id"], name: "index_comments_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.string "password_digest"
t.text "about_me"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Models
class User < ApplicationRecord
has_secure_password
has_many :articles
has_many :comments
end
class Article < ApplicationRecord
belongs_to :user
has_many :comments
validates :user_id, presence: true
end
class Comment < ApplicationRecord
belongs_to :post
belongs_to :user
end
Controller
class ArticlesController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
def index
#articles = Article.all
end
def new
#article = Article.new
end
def create
#user = User.find(params[:user_id])
#article = #user.articles.create(article_params)
if #article.save
redirect_to articles_path
else
redirect_to new_article_path
end
end
def show
end
def edit
end
def update
if #article.update(article_params)
redirect_to :back
else
end
end
def destroy
if #article.destroy
flash[:notice] = "Successfully destroy the article"
redirect_to #article
else
flash[:alert] = "Couldnt delete article"
redirect_to :back
end
end
private
def find_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:title, :body)
end
end
View
<%= form_for(#article, #article.users.build) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :body %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Routes
root 'users#index'
resources :users
resources :articles do
resources :comments
end
If there is something else I might be missing in order to help explain what I'm doing wrong and how to improve/understanding association and building/creating. Please let me know and I'll add the additional information.
For everyone who teaches me/helps me, seriously thank you.

Your form should be
<%= form_for #article do |f| %>
Then in the controller
def create
#article = current_user.articles.build(article_params)
if #article.save
redirect_to articles_path
else
redirect_to new_article_path
end
end

Related

Making a to-do webapp and got such an error SQLite3::SQLException: no such column: tasks.list_id

Showing /home/arthur/Desktop/application/todo/app/views/tasks/index.html.erb where line #7 raised:SQLite3::SQLException: no such column: tasks.list_id
This error appears when I am trying to open the created list to add new tasks. I think the problem is the app can't get the id of the list I am trying to open. But I can't understand what's wrong. (new with ruby and rails). Do I need to add views or something else?
Task Controller
class TasksController < ApplicationController
helper_method :task, :list, :tasks
def create
task.save
redirect_to list_tasks_path(list)
end
def update
task.update task_params
redirect_to list_tasks_path(list)
end
def complete
task.complete
redirect_to list_tasks_path(list)
end
def destroy
task.destroy
redirect_to list_tasks_path(list)
end
private
delegate :tasks, to: :list, private: true
def task
#task ||= params[:id] ? list.tasks.find(params[:id]) : list.tasks.new(task_params)
end
def list
#list ||= List.find params[:list_id]
end
def task_params
params.require(:task).permit(:title, :completed)
end
end
and ListsController
class ListsController < ApplicationController
#helper_method :list, :lists
def index
#lists = List.order('created_at')
end
def new
#list = List.new
end
def create
#list = List.new list_params
#list.save
redirect_to lists_path
end
def edit
#list = List.find params[:id]
redirect_to lists_path
end
def update
#list = List.find params[:id]
#list.update list_params
redirect_to lists_path
end
def destroy
#list = List.find params[:id]
#list.destroy
redirect_to lists_path
end
private
def list_params
params.require(:list).permit(:title)
end
end
View Index.html.erb
<div class="col-md-12">
<h2>Tasks</h2>
<div class="buffer-top"><%= link_to "New Task", new_list_task_path(list), class: 'btn btn-primary' %></div>
<div class="buffer-top">
<% tasks.each do |task| %> <----------- this line
<%= render partial: 'task', object: task %>
<% end %>
</div>
<div class="buffer-top"><%= link_to "Back to Lists", lists_path, class: 'btn btn-primary btn-sm' %></div>
</div>
class Task < ApplicationRecord
belongs_to :lists
def complete!
self.completed = true
save
end
end
class List < ApplicationRecord
has_many :tasks
end
schema
ActiveRecord::Schema.define(version: 2020_04_06_202846) do
create_table "lists", force: :cascade do |t|
t.string "title"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "tasks", force: :cascade do |t|
t.string "title"
t.boolean "completed"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
You have belongs_to :lists in your Task model but no list_id in your corresponding tasks table. Your tasks table needs a migration with t.integer "list_id", :null => false in it.
create_table "tasks", force: :cascade do |t|
t.integer "list_id", :null => false
t.string "title"
t.boolean "completed"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

Adding Comments Section To Posts In Rails

I am trying to add a comments section to posts on my web applications but getting an error when saving the comment
I have been following a tutorial to add a comments section to my posts and have been modifying as I go to work with my app. I am still relatively new to rails and I am still learning. I understand what the error message is telling me, but I am unsure as to how to proceed
Comments Controller:
class CommentsController < ApplicationController
def create
#micropost = Micropost.find_by(id: params[:id])
#comment =
#micropost.comments.create(params[:comment].permit(:body))
end
end
Microposts Contoller:
class MicropostsController < ApplicationController
before_action :logged_in_user, :upvote, :downvote, only:
[:create, :destroy]
before_action :correct_user, :upvote, :downvote, only:
:destroy, allow_destroy: true
def create
#micropost = current_user.microposts.build(micropost_params)
#maximum_length = Micropost.validators_on( :content,
:headline).first.options[:maximum]
if #micropost.save
flash[:success] = "Article Posted"
redirect_to root_url
else
#feed_items = []
render 'articles/home'
end
end
def destroy
#micropost.destroy
flash[:success] = "Micropost deleted"
redirect_to request.referrer || current_user
end
def show
#micropost = Micropost.find(params[:id])
end
private
def micropost_params
params.require(:micropost).permit(:content, :headline)
end
def correct_user
#micropost = current_user.microposts.find_by(id: params[:id])
redirect_to root_url if #micropost.nil?
end
end
Comments Form being rendered on post:
<%= form_for([#micropost, #micropost.comments.build]) do |f| %>
<br>
<p>
<%= current_user.name %>
<%= f.text_area :body %>
</p>
<br>
<p>
<%= f.submit %>
</p>
<% end %>
Comments Model:
class Comment < ApplicationRecord
belongs_to :micropost
end
Microposts Model:
class Micropost < ApplicationRecord
acts_as_votable
has_many :comments
belongs_to :user
validates :user_id, presence: true
validates :headline, presence: true, length: { maximum: 200 }
validates :content, presence: true, length: { maximum: 5000 }
end
Tables:
create_table "comments", force: :cascade do |t|
t.string "name"
t.text "body"
t.bigint "microposts_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "micropost_id"
t.index ["microposts_id"], name:
"index_comments_on_microposts_id"
end
create_table "microposts", force: :cascade do |t|
t.text "content"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "headline"
t.index ["user_id", "created_at"], name:
"index_microposts_on_user_id_and_created_at"
t.index ["user_id"], name: "index_microposts_on_user_id"
end
The form is being rendered on the micropost show view. I can see the form fine.
When I press to save the comment on the post I get an error stating undefined method comments for nil:NilClass and it highlights the Comments controller and the line #comment = #micropost.comments.create(params[:comment].permit(:body))
I know there probably should a method somewhere for comments. The tutorial I watched didn't add anything like that. So I unsure do I need to modify some existing code, or do I need to add a method somewhere called comments?
where is the form to create comments, you are not sending the parameter params [: id], and with this parameter you are looking for the # micropost .. you must send the id in that form, a quick solution could be
<% = f.hidden_field: id, value: # micropost.id%>
 
in the comment creation form
Okay so the answers you all gave pointed me in the right direction. I wasn't actually passing an proper id. Instead of #micropost = Micropost.find_by(id: params[:id]) it should have been #micropost = Micropost.find_by(id: params[:micropost_id])
Many thanks all for getting me there.

Checkbox for removing images in a form with carrierwave

Im creating a blog application in ruby on rails. I have "album" model and a "photo" model. In the album edit view I want to be able to delete the uploaded images which are associated to an album.
Unfortunately I'm getting an undefined method error for checkbox?!
Do you have any solution or hints to make this work?
How can I get to the bottom of why it does not work?
If you need further information just let me know.
albums/edit.html.erb
<%= form_for #album do |f| %>
<% if #album.errors.any? %>
<h2><%= pluralize(#album.errors.count, "error") %> prevent this post from saving:</h2>
<ul>
<% #album.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>k
</ul>
<% end %>
<div class="blog_edit_wrapper">
<%= f.label :title %><br>
<%= f.text_field :title, class: "blog_edit_title" %>
<br>
<br>
<%= f.submit 'Submit', class: "blog_edit_submit" %>
</div>
<% end %>
<hr>
<% #album.photos.each do |photo| %>
<%= image_tag(photo.gallery_image) %>
<%= photo.check_box :remove_gallery_image %>
<br>
<br>
<%= f.submit 'Submit', class: "blog_edit_submit" %>
<% end %>
photos_controller.rb
class PhotosController < ApplicationController
before_action :find_photo, only: [ :show, :edit, :update, :destroy]
before_action :set_album
def index
#photo = Photo.all
end
def new
#photo = #album.photos.new
end
def show
end
def create
#photo = #album.photos.new photo_params
#photo.album = #album
if #photo.save
redirect_to #album
else
render :new
end
end
def edit
end
def update
#photo = #album.photos.find params[:id]
if #photo.update photo_params
redirect_to #album, notice: "Your photo was successfully saved!"
else
render 'edit'
end
end
def destroy
#photo.destroy
redirect_to photos_path
end
private
def set_album
#album = Album.find params[:album_id]
end
def photo_params
params.require(:photo).permit(:gallery_image, :album_id, :title, :remove_gallery_image)
end
def find_photo
#photo = Photo.find(params[:id])
end
end
photo.rb
class Photo < ActiveRecord::Base
mount_uploader :gallery_image, ImageUploader
belongs_to :album
end
albums_controller.rb
class AlbumsController < ApplicationController
before_action :find_album, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#albums = Album.all.order("created_at desc").paginate(page: params[:page], per_page: 12)
end
def new
#album = Album.new
end
def show
#photo = Photo.all
end
def create
#album = Album.new album_params
if #album.save
redirect_to #album
else
render :new
end
end
def edit
end
def update
if #album.update album_params
redirect_to #album, notice: "Your article was successfully saved!"
else
render 'edit'
end
end
def destroy
#album.destroy
redirect_to albums_path
end
private
def album_params
params.require(:album).permit(:title)
end
def find_album
#album = Album.find(params[:id])
end
end
album.rb
class Album < ActiveRecord::Base
has_many :photos
end
schema.rb
ActiveRecord::Schema.define(version: 20170424131600) do
create_table "albums", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
end
add_index "friendly_id_slugs", ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
add_index "friendly_id_slugs", ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
add_index "friendly_id_slugs", ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id"
add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type"
create_table "photos", force: :cascade do |t|
t.string "gallery_image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "album_id"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.string "post_main_image"
end
add_index "posts", ["slug"], name: "index_posts_on_slug", unique: true
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
I believe your issue is that you're not using a form but just iterating over the photos.
Also you can place the code for editing the photos inside the first form.
Place this code below the <br> tags and remove the <% #album.photos.each do |photo| %> interation.
<%= fields_for(#album, #album.photos.build) do |f| %>
<%= image_tag(f.gallery_image)%>
<%= f.check_box :remove_gallery_image %>
<% end %>
Edit:
To clarify the above; place the aforementioned code inside your original edit #album form and remove the iteration for the #album.photos.each

Rails One-To-Many Nested Form - Error using controller show action to view posted form?

I'm trying to create a posting form to post a url & some text. The nested form submits without an error but I can't display the subsequent content of that form in my show action controller.
Post Model
class Post < ActiveRecord::Base
has_many :texts
has_many :urls
accepts_nested_attributes_for :texts, :urls
end
Text Model
class Text < ActiveRecord::Base
belongs_to :post
end
Url Model
class Url < ActiveRecord::Base
belongs_to :post
end
Post Controller
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
#texts = #post.texts
#urls = #post.urls
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:texts_attributes => [:textattr], :urls_attributes => [:urlattr])
end
show.html.erb
<%= #text.textattr %>
<%= #url.urlattr %>
Database Schema
create_table "posts", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "texts", force: :cascade do |t|
t.text "textattr"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
add_index "texts", ["post_id"], name: "index_texts_on_post_id"
create_table "urls", force: :cascade do |t|
t.string "urlattr"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
add_index "urls", ["post_id"], name: "index_urls_on_post_id"
end
Error message after I press submit on the form
!(http://imgur.com/dzdss5z)
Your help would be amazing - thank you!
The #text and #url variables are never set in the controller's show action, so they are nil. Hence, there is an error when you try to call those attributes from them in the view.
You have set the #texts and #urls variables, so you can do something like this:
<% #texts.each do |text| %>
<%= text.textattr %>
<% end %>
<% #urls.each do |url| %>
<%= url.urlattr %>
<% end %>

Creating a form for a controller inside the show of another controller

I am currently using Rails 4 to create a website and I need to create a form for a model "candidature" inside a model "post" using another model "reponse".
This the post model :
class Post < ActiveRecord::Base
validates :title, presence: true,
length: { minimum: 5 }
belongs_to :entrepreneur
belongs_to :categorie
has_many :candidatures
accepts_nested_attributes_for :candidatures
has_many :questions
accepts_nested_attributes_for :questions,
:reject_if => lambda { |a| a[:enonce].blank? },
:allow_destroy => true
end
The candidature model :
class Candidature < ActiveRecord::Base
has_many :reponses
accepts_nested_attributes_for :reponses, :allow_destroy => true
end
And the reponse model :
class Reponse < ActiveRecord::Base
belongs_to :candidature
end
I don't have controllers for candidature and reponse, because i don't think i need any (do correct me if I'm wrong).
I have created posts that are projects and in the show view of posts, i need to create a form where a guest can answer some questions through answer and all those answers have to be saved in one candidature.
The schema.rb looks like that :
ActiveRecord::Schema.define(version: 20130718083016) do
create_table "candidatures", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "post_id"
end
create_table "questions", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "post_id"
t.text "enonce"
end
create_table "reponses", force: true do |t|
t.integer "candidature_id"
t.datetime "created_at"
t.datetime "updated_at"
t.text "enonce"
end
create_table "posts", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.text "defi"
t.text "mission"
t.text "competences"
t.text "gain"
t.text "lieny"
t.text "liendb"
t.string "link"
end
The controller for post :
class PostsController < ApplicationController
layout :resolve_layout
include Candidaturetopost
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
flash[:notice] = "Successfully created project."
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
#post.candidatures.build
end
def index
#posts = Post.all
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
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, :image, :defi, :mission, :competences, :gain, :lieny, :liendb, :link, questions_attributes: [:enonce, :post_id, :id, :_destroy],
candidatures_attributes: [:post_id, :id, reponses_attributes: [:candidature_id, :id, :enonce]])
end
The show view i have tried to get working :
<%= form_for #post do |f| %>
<%= f.fields_for :candidatures do |cform| %>
<ol>
<% for question in #post.questions %>
<li><%= question.enonce %></li>
<%= cform.fields_for :reponses do |rform| %>
<%= rform.text_area :enonce %>
<% end %>
<% end %>
</ol>
<%= cform.submit %>
<% end %>
<% end %>
With the code shown here, the text_area for enonce isn't even displayed.
Is what I want to do even possible ? How can I have something similar if not ?
Try this
#post.candidatures.build
#post.candidatures.each {|candidature| candidature.responses.build }
But as I wrote in comment you overcomplicated the model structure and I belive you should rethink it.
You were right, it was way too complicated.
I used this to help me get it working, I have now the links I wanted between my three models.

Resources