collection_select doesn't save through form - ruby-on-rails

I know there is a lot of similar posts where people have the same problem, but none of them helped me. If i create new article then it won't have a category. But if i edit article created earlier in seed.rb then the category is updated.
What's wrong?
Categories table:
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end
category.rb
class Category < ActiveRecord::Base
has_many :articles
end
article.rb
class Article < ActiveRecord::Base
belongs_to :category
end
and then i have a _form file
<%= form_for(#article) do |f| %>
<div class="title">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="content">
<%= f.label :content %>
<%= f.text_field :content %>
</div>
<div class="category">
<%= f.label :category %>
<%= collection_select(:article, :category_id, Category.all, :id, :name) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There is a categories_controller file:
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def show
#category = Category.find(params[:id])
#articles = #category.articles
end
def new
#category = Category.new
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to(:action => 'index')
else
render('new')
end
end
def edit
#category = Category.find(params[:id])
end
def update
#category = Category.find(params[:id])
if #category.update_attributes(category_params)
redirect_to(:action => 'show', :id => #category.id)
else
render('index')
end
end
def delete
#category = Category.find(params[:id])
end
def destroy
Category.find(params[:id]).destroy
redirect_to(:action => 'index')
end
private
def category_params
params.require(:category).permit(:name)
end
end
Articles controller file:
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to(:action => 'index')
else
render('new')
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update_attributes(article_params)
redirect_to(:action => 'show', :id => #article.id)
else
render('index')
end
end
def delete
#article = Article.find(params[:id])
end
def destroy
Article.find(params[:id]).destroy
redirect_to(:action => 'index')
end
private
def article_params
params.require(:article).permit(:title, :content)
end
end

It looks like you're not building the association in the articles#create action. The category_id is being sent through your form, but you still need to to build the Active Record association. You could try something like this in the articles controller:
def create
#article = Article.new(article_params)
#category = Category.find(params[:category_id])
#article.category = #category
if #article.save
redirect_to(:action => 'index')
else
render('new')
end
end
Keep in mind, there are multiple ways to create an association. Your Article class has the following five methods to manipulate the association:
#article.category
#article.category=
#article.build_category
#article.create_category
#article.create_category!

Related

Ruby on Rails NoMethodError in Articles#show

I keep getting a no method error. Why? How can I fix this?
NoMethodError in Articles#show
undefined method `photo' for #
I am using ruby on rails and I'm trying to use paperclip so i can upload photos on my app
part of my show file
<%= render #article.photos %> #source of error
<h3>Add a photo:</h3>
<%= render 'photos/form' %>
my photos controller
class PhotosController < ApplicationController
#Index action, photos gets listed in the order at which they were created
def index
#photos = Photo.order('created_at')
end
#New action for creating a new photo
def new
#photo = Photo.new
end
#Create action ensures that submitted photo gets created if it meets the requirements
def create
#article = Article.find(params[:article_id])
#photo = #article.photos.create(photo_params)
redirect_to article_path(#article)
end
def destroy
#article = Article.find(params[:article_id])
#photo = #article.photos.find(params[:id])
#photo.destroy
redirect_to article_path(#article)
end
private
#Permitted parameters when creating a photo. This is used for security reasons.
def photo_params
params.require(:photo).permit(:title, :image)
end
end
========= UPDATE =======
This is my
articles controller
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
article model
class Article < ApplicationRecord
has_many :comments
end
I fixed it now, but now i have another no method error
undefined method `article_photos_path' for #<#:0x007f17f052d0a0>
Did you mean? article_path
<%= form_for([#article, #article.photos.build]) do |f| %> #source of error
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control'%>
</div>
<p>
<%= f.submit 'Upload Photo' %>
</p>
<% end %>
</p>
<% end %>
Being Photo another model so, you need to make the proper relationship:
class Article < ApplicationRecord
has_many :comments
has_many :photos
end
class Photo < ApplicationRecord
belongs_to :article
end
As I see in your photo_params, you don't have the article_id attribute then you must add it, running a migration:
$ rails g migration add_article_to_photos article:references
$ rails db:migrate
After that you should update them:
params.require(:photo).permit(:title, :image, :article_id)

No route matches while creating nested resource in Rails

I am trying to create a new teacher for a specific school in my project and I got this error:
No route matches [POST] "/schools/3/teachers/new"
Here is my teachers_controller.rb:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def create
#teacher = Teacher.new(teacher_params)
#teacher.save
redirect_to school_path(school)
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
end
schools_controller.rb:
class SchoolsController < ApplicationController
def show
#school = School.find(params[:id])
end
def new
#school = School.new
end
def edit
#school = School.find(params[:id])
end
def update
#school = School.find(params[:id])
if #school.update(school_params)
redirect_to #school
else
render 'edit'
end
end
def index
#schools = School.all
end
def create
#school = School.new(school_params)
if #school.save
redirect_to schools_path
else
render 'new'
end
end
def destroy
#school = School.find(params[:id])
#school.destroy
redirect_to schools_path
end
private
def school_params
params.require(:school).permit(:name)
end
end
routes.rb:
Rails.application.routes.draw do
resources :schools do
resources :teachers
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'welcome#index'
And teachers/new.html.erb:
<%= form_for :teacher, url: school_teachers_path(school) do |f| %>
<p>
<%= f.label :firstName %><br>
<%= f.text_field :firstName %>
</p>
<p>
<%= f.label :lastName %><br>
<%= f.text_field :lastName %>
</p>
<p>
<%= f.label :middleName %><br>
<%= f.text_field :middleName %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
As your teacher resource is nested under the school resource, so you need to pass the school when you try to create a teacher.
Try changing your new and create actions in teachers_controller.rb to something like this:
def new
#school = School.find(params[:school_id])
#teacher = #school.teachers.build
end
def create
#school = School.find(params[:school_id])
#teacher = #school.teachers.build(params[:teacher])
#teacher.save
redirect_to school_path(#school)
end
And, then change your form to this:
<%= form_for([#school, #teacher]) do %>
. . .
. . .
<% end %>
Try this in your form:
<%= form_for [school, Teacher.new] do |f| %>
The path you are posting to is for the index of teachers at a school:
school_teachers GET /schools/:school_id/teachers(.:format) teachers#index
I believe that it's a has_many belongs_to association. So you need to first change your teacher controller create action and new action.
class TeachersController < ApplicationController
def new
get_school
#teacher = #school.teachers.build
end
def create
get_school
#teacher = #school.teachers.build(teacher_params)
If #teacher.save
redirect_to school_path(school)
else
render 'new'
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
def get_school
#school = School.find (params [:school_id])
end
end
Then in your form you 'll do :
<%= form_for([#school,#teacher]) do |f| %>
Hope this will help

Having a comment obtain a community_id as well

I've tried figuring out the issue behind not being able to save the community_id I hope someone can help me with.
MODELS
User
has_one :profile
has_many :communities, dependent: :destroy
has_many :comment, dependent: :destroy
Community
extend FriendlyId
friendly_id :title, use: [:slugged, :finders]
has_many :comments
belongs_to :user
Comment
belongs_to :user
belongs_to :community
belongs_to :profile
CONTROLLERS
Communities
def index
#communities = Community.all
#comment = Comment.new
#comments = Comment.all
end
def create
#community = Community.new(community_params)
#community.user_id = session[:user_id]
if #community.save
flash[:notice] = "Post Created"
else
flash[:alert] = "Error post not created"
end
redirect_to "/"
end
def new
#community = Community.new
end
def edit
#community = Community.friendly.find(params[:id])
end
def show
#comment = Comment.new
#comments = Comment.all
#community = Community.friendly.find(params[:id])
#current_user = User.find(session[:user_id])
end
def update
#community = Community.friendly.find(params[:id])
if #community.update(params[:comment])
flash[:notice] = "post updated"
else
flash[:alert] = "post not updated"
end
end
def destroy
#community = Community.friendly.find(params[:id])
if #community.destroy
flash[:notice] = "Post was thrown away"
else
flash[:alert] = "Post was not deleted"
end
redirect_to "/"
end
private
def community_params
params.require(:community).permit(:user_id, :title, :bio)
end
Comments
def index
#comments = Comment.all
end
def create
#comment = Comment.new(comment_params)
#comment.user_id = session[:user_id]
if #comment.save && #comment.community_id
flash[:notice] = "Comment has been posted"
else
flash[:alert] = #comment.errors.full_messages
end
redirect_to :back
end
def new
#comment = Comment.new
end
def show
#comment = Comment.find(params[:id])
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
redirect_to :back
end
private
def comment_params
params.require(:comment).permit(:text, :user_id, :community_id, :profile_id)
end
VIEWS
comments/_new
<%= form_for #comment do |f| %>
<%= f.hidden_field :community_id %>
<%= f.text_area :text, placeholder: "Enter New Comment Here ...", :cols => 50, :rows => 3, :class => 'text_field_message', :id => 'new_comment' %>
<%= f.submit :class => 'new_comment_button' %>
<% end %>
Whenever I check my console I notice the user_id gets registered with the comment but community_id is nil. Could someone point me in the right direction or help me understand where I made an error. Thank you for all your help.
Firstly,
#app/models/user.rb
has_many :comments, dependent: :destroy #-> this should be plural.
You have no value in your community_id input attribute:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
end
#app/views/comments/new.html.erb
<%= form_for #comment do |f| %>
<%= f.hidden_field :community_id, params[:community_id] %>
<% end %>
I am assuming you're passing your :community_id parameter through the routes (IE url.com/communities/:community_id/comments/new)
I would do the following:
#config/routes.rb
resources :communities do
resources :comments
end
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
def create
#comment = Comment.new comment_params
#comment.save
end
private
def comment_params
params.require(:comment).permit(:text).merge(user_id: current_user.id, community_id: params[:community_id])
end
end
This will give you the ability to use the following view:
#app/views/comments/new.html.erb
<%= form_for #comment do |f| %>
<%= f.text_area :text, placeholder: "Enter New Comment Here ...", :cols => 50, :rows => 3, :class => 'text_field_message', :id => 'new_comment' %>
<%= f.submit :class => 'new_comment_button' %>
<% end %>

Getting nested form to work rails?

I have these models:
class List < ActiveRecord::Base
has_many :list_items, :dependent => :destroy
accepts_nested_attributes_for :list_items, :reject_if => lambda { |a| a(:task.blank?)}
end
class ListItem < ActiveRecord::Base
belongs_to :list
end
and this controller:
class ListsController < ApplicationController
def index
#lists = List.order("lists.created_at DESC")
end
def show
#list = List.find(params[:id])
end
def new
#list = List.new({:name => Time.now.strftime("%A %d %B")})
3.times { #list.list_items.build}
end
def create
#list = List.new(list_params)
if #list.save
flash[:notice] = "List successfully added."
redirect_to(:action => 'index')
else
render(:action => 'new')
end
end
def edit
#list = List.find(params[:id])
end
def update
#list = List.find(params[:id])
if #list.update_attributes
flash[:notice] = "List updated successfully."
redirect_to(:action => 'index')
else
render(:action => 'edit')
end
end
def delete
#list = List.find(params[:id])
end
def destroy
#list = List.find(params[:id]).destroy
flash[:notice] = "List successfully deleted"
redirect_to(:action => 'index')
end
private
def list_params
params.require(:list).permit(:name, :task)
end
end
and this form:
<%= form_for #list do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :list_items do |builder| %>
<p>
<%= builder.label :task %><br />
<%= builder.text_field :task %>
</p>
<% end %>
<p><%= f.submit "Create" %></p>
<% end %>
You can probably see what I am trying to do -> create a form where it creates a new list and then adds task to that list but for some reason whenever I hit submit on the form the name stays but tasks don't save?
I solved the problem turns out i needed to add the list_item attributes to the list controller. I was trying to do this the rails 3 way in teh model with attr_accessible which kept giving me an error. I needed to update the controller to have this at the bottom:
def list_params
params.require(:list).permit(:name, :list_items_attributes => :task)
end

how to fetch most recent records from db in ruby on rails and where to write this query

I want to fetch 5 most recent artilce's titles from my db in ruby on rails. I have already fetched( fetch all article' title) article's title but those are not restricted by this (5 most recent) condition. Where to write to this logic, either in controller or in model part. If it should be written in model then how to access it in views part. Whether it will be written in controller part. Please suggest me.
article model
class Article < ActiveRecord::Base
attr_accessible :title, :body
attr_accessible :tag_list
has_many :comments
belongs_to :user
has_many :taggings
has_many :tags, through: :taggings
validates :title, :body, :tag_list, :presence => true
def tag_list
self.tags.collect do |tag|
tag.name
end.join(", ")
end
def tag_list=(tags_string)
tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
new_or_found_tags = tag_names.collect { |name| Tag.find_or_create_by_name(name) }
self.tags = new_or_found_tags
end
end
articles_controller.rb
class ArticlesController < ApplicationController
before_filter :is_user_admin, only: [:new, :create, :edit, :destroy]
def is_user_admin
redirect_to(action: :index) unless current_user.try(:is_admin?)
return false
end
def index
#articles = Article.all(:order => "created_at DESC")
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(params[:article])
#article.user_id = current_user.id
if #article.save
flash[:success] = "article created!"
redirect_to article_path(#article)
else
render 'new'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to action: 'index'
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update_attributes(params[:article])
flash.notice = "Article '#{#article.title}' Updated!"
redirect_to article_path(#article)
else
render 'edit'
end
end
end
article/index.rb
<div style="background-color:#1fb2e8; color:#FFFFFF; font-size: 1.6em"> recent article </div>
<div style="font-size: 1.3em">
<% #articles.each do |article| %>
<div style="margin-top:15px; margin-left:8px"> <%= link_to article.title.first(5), article_path(article) %></div>
<% end %>
I tried to fetch using first or last(5), but did not worked. How to get 5 or 10 recent titles. Please suggest me.
A scope might be a nice way to do this
scope :most_recent, :order => "created_at DESC", :limit => 5
Rails 3.2 Scope Doc
hello write this logic in model
please refer following links
Find the newest record in Rails 3

Resources