I have two models post and topic in my rails app
class Post < ActiveRecord::Base
#relation between topics and post
belongs_to :topic
#post is valid only if it's associated with a topic:
validates :topic_id, :presence => true
#can also require that the referenced topic itself be valid
#in order for the post to be valid:
validates_associated :topic
end
And
class Topic < ActiveRecord::Base
#relation between topics and post
has_many :posts
end
I am trying to create association between both of them.
I want multiple post corresponding to each topic
I have used nested routes
Rails.application.routes.draw do
# nested routes
resources :topics do
resources :posts
end
resources :userdetails
devise_for :users, :controllers => { :registrations => "registrations" }
My Post controller looks like
class PostsController < ApplicationController
# before_action :set_post, only: [:show, :edit, :update, :destroy]
before_filter :has_userdetail_and_topic, :only =>[:new, :create]
# GET /posts
# GET /posts.json
#for new association SAAS book
protected
def has_userdetail_and_topic
unless(#topic =Topic.find_by_id(params[:topic_id]))
flash[:warning] = 'post must be for an existing topic'
end
end
public
def new
#post = #topic.posts.build
###topic = Topic.find(params[:topic_id1])
end
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
##topic.posts << #post
##current_user = current_user.id
#current_user.posts << #topic.posts.build(params[:post])
##post = Post.new(post_params )
##post.userdetail_id = current_user.id
#Association functional between topic and post
#Class variable used
###topic.posts << #post
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:topic_id,:issue, :description, :rating, :userdetail_id)
end
end
I am trying to navigate from topics/index via code <td><%= link_to 'Write', new_topic_post_path(#topic) %> </td>
but when i try to go at localhost:3000/topics]
I am getting error
No route matches {:action=>"new", :controller=>"posts", :topic_id=>nil} missing required keys: [:topic_id]
Can any body tell me about this error, as i am new to rails please clearly specify answer.
And I have one more doubt, please tell me if i am doing association between topic and post incorrectly.I have confusion about this line of code -
#topic.posts << #post
What the error missing required keys: [:topic_id] is telling you is that you need to provide a hash with the key topic_id:
<%= link_to 'Write', new_topic_post_path(topic_id: #topic) %>
Passing a resource as to a route helper only works for the id param:
<%= link_to #topic, topic_path(#topic) %>
Is a kind of shorthand for:
<%= link_to #topic, topic_path(id: #topic.to_param) %>
Addition:
#prcu is also correct. The #topic record needs to be saved to the database. Records which are not saved do not have an id since the database assigns the id column when the record is inserted.
You also need to set the #topic instance variable in PostsController:
#topic = Topic.find(params[:id])
This is commonly done with a before filter:
before_filter :set_topic, only: [:new]
def set_topic
#topic = Topic.find(params[:id])
end
The same also need to be done in TopicsController#index.
#topic is not set or it's not persisted. You can not use topic not saved to db in this helper.
Related
I want to have a page that displays links to other websites in my project. I created links.html.erb in my customers views but when I try access the page I get this error.
ActiveRecord::RecordNotFound in CustomersController#show
Couldn't find Customer with 'id'=links
Customers Controller:
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /customers
# GET /customers.json
def index
#customers = Customer.all
#q = Tour.search(params[:q])
#tours = #q.result.page(params[:page]).per(5)
#q.build_condition if #q.conditions.empty?
#q.build_sort if #q.sorts.empty?
end
def links
end
# GET /customers/1
# GET /customers/1.json
def show
#customers = Customer.all
end
def welcome
end
# GET /customers/new
def new
#customer = Customer.new
end
# GET /customers/1/edit
def edit
end
# POST /customers
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /customers/1
# PATCH/PUT /customers/1.json
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /customers/1
# DELETE /customers/1.json
def destroy
#customer.destroy
respond_to do |format|
format.html { redirect_to customers_url, notice: 'Customer record successfully deleted' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
#customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:name, :address, :telephone_no, :ticket_number)
end
end
Routes:
Rails.application.routes.draw do
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :customers
resources :tours
devise_for :users
root 'customers#welcome'
In view:
<% if current_user.customer? %>
<div class="col-sm-4">
<%= link_to image_tag("image1.jpg", size: "300x300"), {:controller => 'customers', :action => "links" } %>
<h3>Links</H3>
</div>
<% end %>
Anyone help with what is wrong here? Thanks.
Add get 'links' => 'customers#links', as: :link to the routes.rb and update your link as:
<%= link_to image_tag("image1.jpg", size: "300x300"), link_path %>
Here's a bit of an expansion on Ganesh's answer.
When you do this:
<%= link_to image_tag("image1.jpg", size: "300x300"), {:controller => 'customers', :action => "links" } %>
You're creating a url to:
customers/links
In your routes, the first match for customers/links is customers/:id which routes to customers/show with params[:id] = 'links'. See the Guide if you don't understand why this is true. That's why you're getting the error:
ActiveRecord::RecordNotFound in CustomersController#show
Couldn't find Customer with 'id'=links
As Ganesh correctly points out, you can coerce the routes exactly as he says. To me, it is a little smelly to put this links page in the CustomerController and to coerce the routes. But, that's really a design decision based on the problem(s) you're trying to solve.
I am new to rails I created post model and posts_controller which has Name:string, EMail:string, Message:text, topic_id:integer columns using scaffold.
I also created a topic model and topics_controller which has Topic_Name:string in it.
I provided the relationship among the models as follows:
class Topic < ActiveRecord::Base
has_many :posts, foreign_key: 'topic_id'
end
class Post < ActiveRecord::Base
belongs_to :topic
end
In routes.db I created the nested resources as:
resources :topics do
resources :posts
end
topics_controller.rb code:
class TopicsController < ApplicationController
before_action :set_topic, only: [:show, :edit, :update, :destroy]
# GET /topics
# GET /topics.json
def index
#topics = Topic.all
end
# GET /topics/1
# GET /topics/1.json
def show
end
# GET /topics/new
def new
#topic = Topic.new
end
# GET /topics/1/edit
def edit
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(topic_params)
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render :show, status: :created, location: #topic }
else
format.html { render :new }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /topics/1
# PATCH/PUT /topics/1.json
def update
respond_to do |format|
if #topic.update(topic_params)
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { render :show, status: :ok, location: #topic }
else
format.html { render :edit }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url, notice: 'Topic was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_topic
#topic = Topic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def topic_params
params.require(:topic).permit(:Name)
end
end
posts_controller code:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:Name, :Email, :Message, :topic_id)
end
end
I need to group posts using the topic. i.e., On clicking show on a particular topic it should go to the URL /topics/<topic_id>/posts where it should lists all posts related to that topic and I can create/delete posts belongs to that topic.
Can anyone help doing this..
Thank you..
Your question should be more direct, there's a lot of information that aren't related to the problem (the attributes names, for example), and your goal isn't clear enough.
It seems that you just want to setup the routes, right? You already have all posts related to that topic though the association: topic.posts. You just need to setup nested resource routes for posts:
resources :topics do
resources :posts
end
Also, you don't need the foreign_key option since you're using the naming conventions. It seems as well that you named some attributes in upper case, they should be name, email and message.
UPDATE:
In the index action, since you want posts belonging to one topic, you need to scope the #posts instance variable. Since you're using nested resources, you have the parameter params[:topic_id], so just fetch the topic with #topic = Topic.find(params[:topic_id]), then scope the association with #posts = #topic.posts. You'll need to do the same for every other action. I recommend that you read a little about associations in Rails, you'll probably need to use methods like #topic.posts.build and #topic.posts.find(params[:id]).
I found the solution for this problem in this link: Nested resources
Download the source code and find the solution...
I searched about this question, but had no success.
I´m trying to learn ruby on rails, came from php. I generated a webapp with the generation tool, second I generated a News controller with scaffold. The devise and pundit are installed too with gems.
The program works perfectly, the problem is related to the News module, I generated it with scaffold.
The routes where created with the command: resources :news
My idea is to create one _form.html.erb and it be called to create a new record or to updated an existing record. Some tutorials teach to create a new.html.erb and an update.html.erb file and duplicate the code, but I know that is possible to have partials as the main form part.
I´m using simple_form_for and the code to do the new is:
# GET /news/new
def new
#news = New.new
authorize New
end
The _form.html.erb
<%= simple_form_for(#news) do |f| %>
<%= f.input :titulo %>
<%= f.input :resumo %>
<%= f.button :submit %>
<% end %>
When I enter to edit, it works, but to add a new it throws.
ActionController::UrlGenerationError at /news/new
No route matches {:action=>"show", :controller=>"news", :locale=>:en} missing required keys: [:id]
Sorry for my bad english, I´m without direction here, is there any way that I can solve it?
Thanks.
====== UPDATED =======
routes.rb
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users
resources :news
end
New.rb (Model)
class New < ActiveRecord::Base
belongs_to :user
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :set_locale
def default_url_options(options={})
{ locale: I18n.locale }
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
news_controller.rb (Complete)
class NewsController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized
#before_action :set_news, only: [:show, :edit, :update, :destroy]
# GET /news
# GET /news.json
def index
#news = New.all
authorize New
end
# GET /news/1
# GET /news/1.json
def show
#news = New.find(params[:id])
authorize New
end
# GET /news/new
def new
#news = New.new
authorize New
end
# GET /news/1/edit
def edit
#news = New.find(params[:id])
authorize New
end
# POST /news
# POST /news.json
def create
#news = New.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'New was successfully created.' }
format.json { render :show, status: :created, location: #news }
else
format.html { render :new }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /news/1
# PATCH/PUT /news/1.json
def update
respond_to do |format|
if #news.update(news_params)
format.html { redirect_to #news, notice: 'New was successfully updated.' }
format.json { render :show, status: :ok, location: #news }
else
format.html { render :edit }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# DELETE /news/1
# DELETE /news/1.json
def destroy
#news.destroy
respond_to do |format|
format.html { redirect_to news_url, notice: 'New was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_news
#news = New.find(params[:id])
end
private
def news_params
params.require(:news).permit(:titulo, :resumo, :texto, :published_at, :user_id)
end
end
Command rake routes
news_index GET /news(.:format) news#index
POST /news(.:format) news#create
new_news GET /news/new(.:format) news#new
edit_news GET /news/:id/edit(.:format) news#edit
news GET /news/:id(.:format) news#show
PATCH /news/:id(.:format) news#update
PUT /news/:id(.:format) news#update
DELETE /news/:id(.:format) news#destroy
Thanks in advance.
======= UPDATE 2 ===========
Changing my New action to this:
def new
#news = New.create(params[:id])
end
It solved, but everytime I enter, it creates an empty record...
Use news_index_path for GET /news and POST /news. Rails doesn't figure out the pluralization correctly for the "news" term.
Check the output of rake routes, it will be obvious.
i have been stuck on this problem for a while now and have searched through solution after solution and so far, the ones i have come across do not work.
i made a new rails scaffold for a new Object for my application, i have the table set up and i can view the Post objects when i run the server.
The problem when i go to view the Post objects when my server is running, it's content does not display, and i cannot update the objects this error gets thrown:
param is missing or the value is empty: post
The Posts table in the database looks like this:
posts table
As you can see, the field content has data that i want to display on my page when i go to view said Post.
This is what comes up instead:
what i see when running the server
AS you can see, it wont display the content of the content field.
This is my posts_controller.rb
class PostsController < ApplicationController
# you may want to udpate these posts? typo's outdated info?
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:content)
end
end
i thought this would allow me to see the content
def post_params
params.require(:post).permit(:content)
end
And i thought this is what defines:post because of before_action :set_post, only: [:show, :edit, :update, :destroy]
def set_post
#post = Post.find(params[:id])
end
This is what is shown on the error page in rails:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tHFQAWv08aUoi7ndZsVC1aCNJkYP6hE8w+89NTTpBjc=",
"commit"=>"Update Post",
"id"=>"2"}
I am really confused to why this is happening, im new to rails so no doubt im missing something basic.
Thanks,
Chris.
Your request is missing the post param:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tHFQAWv08aUoi7ndZsVC1aCNJkYP6hE8w+89NTTpBjc=",
"commit"=>"Update Post",
"id"=>"2"}
This is most likely due to an error in the form in your app/views/posts/edit.html.erb view. The form should look something like this:
<%= form_for #post, url: {action: "edit"} do |f| %>
<%= f.text_area :content %>
<%= end %>
You can read more about forms in the rails guides.
would someone be able to help me understand this error. I am trying to create a contact form in rails following the building web apps tutorial. I followed the steps to generate a message scaffold. I then amended my routes. Next it said to put this into the messages controller show action.
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
I have done this and i am getting the following error
ActiveModel::ForbiddenAttributesError in MessagesController#create
ActiveModel::ForbiddenAttributesError
This is my message controller file
class MessagesController < InheritedResources::Base
def show
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end
end
My routes file is as follows
# devise_for :users
resources :products do
resources :orders, only: [:new, :create]
#tells rails needs product id number
end
# get 'pages/payment'
get 'home/about'
get 'messages/new'
get 'seller' => "products#seller"
get 'sales' => "orders#sales"
get 'static_pages/productlanding'
get "content/veg"
get "content/fruit"
get "content/mix"
get 'subscriptions/new'
root 'static_pages#home'
Why are you saving in the show action?
--
Params
The ForbiddenAttributes error stems from the strong_params functionality of Rails.
When saving data, you're meant to pass the params through to your model through a strong_params method. This is typically achieved with the following setup:
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def show
#message = Message.find(params[:id])
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
#message.save
end
private
def message_params
params.require(:message).permit(:your, :message, :params)
end
end
This is how your controller should really be constructed. Your error, I believe, is caused by your lack of params to pass through to the attributes in your model (hence your call to #save resulting in trying to populate your model with non-data).
Strange. You execute saving method in "show" method of controller which responsible for showing up the content on the separate page.
You should replace as following:
def create
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end
i have managed to sort this with the following! Thanks for all the help
class MessagesController < ApplicationController
before_action :set_message, only: [:show, :edit, :update, :destroy]
# GET /messages
# GET /messages.json
def index
#messages = Message.all
end
# GET /messages/1
# GET /messages/1.json
def show
end
# GET /messages/new
def new
#message = Message.new
end
# GET /messages/1/edit
def edit
end
# POST /messages
# POST /messages.json
def create
#message = Message.new(message_params)
respond_to do |format|
if #message.save
flash.now[:notice] = 'Thank you for your message!'
format.html { redirect_to root_path }
format.json { render :show, status: :created, location: #message }
else
format.html { render :new }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /messages/1
# PATCH/PUT /messages/1.json
def update
respond_to do |format|
if #message.update(message_params)
format.html { redirect_to #message, notice: 'Message was successfully updated.' }
format.json { render :show, status: :ok, location: #message }
else
format.html { render :edit }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# DELETE /messages/1
# DELETE /messages/1.json
def destroy
#message.destroy
respond_to do |format|
format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_message
#message = Message.find(params[:id])
end
.
def message_params
params.require(:message).permit(:name, :email, :company, :phone, :subject, :body)
end
end
I was facing this same error. The fix was to make the params function name same as the root tag of the post json like below
Post json
{"jobseeker_certificate":{"id":-1,"name":"First Class Medical Certificate","institute":"GACA","attachment":null}}
In Controller i changed jobseeker_aircraft_type_ratings_params to jobseeker_certificate_params
def jobseeker_certificate_params
params.require(:jobseeker_certificate).permit(:aircraft, :total_time, :pilot_in_command,
:co_pilot, :rating_expiry_date, :from, :to, :jobseeker_id, :grade, :institute, :attachment, :name,
:from, :to, :jobseeker_id, :grade, :institute, :attachment, :name, :sector_id, :certificate_type,
:details, :certificate_type, :details)
end