I've been following the tutorial on creating a Rails blog (http://www.roberthuberdeau.com/articles/4-How-to-create-a-blog-in-Ruby-on-Rails-3) and have basically got all the way to the end.
However, after all the migrations I'm now struggling. Whenever I complete the form I previously used to create articles, I can't see them on the index page. I've dug around and believe the root of the error is that I'm not saving any articles when I press 'create article'.
To test this, I created an article using the console and this is appearing as it should so I think the problem lies somewhere between the form that creates articles and the controller (though am happy to be corrected on this).
Whenever I try the following appears in the logs:
Started POST "/articles" for 127.0.0.1 at 2013-04-01 21:12:58 +0100
Processing by ArticlesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XLeHm+4Tgd6n9vt4RxAQ5YVTbWTi+UnqkmBso9Iuo+4=", "article"=>{"title"=>"I rule", "body"=>"Change teams.", "tag_names"=>"kill", "published"=>"1"}, "commit"=>"Create Article"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Admin' LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Moderator' LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Member' LIMIT 1
Redirected to http://localhost:3000/
Completed 302 Found in 5ms (ActiveRecord: 0.5ms)
With the database schema:
ActiveRecord::Schema.define(:version => 20130401171646) do
create_table "articles", :force => true do |t|
t.string "title"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id", :null => false
t.boolean "published", :default => false
end
create_table "comments", :force => true do |t|
t.integer "article_id"
t.string "name"
t.string "email"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "roles_users", :id => false, :force => true do |t|
t.integer "role_id"
t.integer "user_id"
end
create_table "taggings", :force => true do |t|
t.integer "article_id"
t.integer "tag_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "tags", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true 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
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
Articles controller:
class ArticlesController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
# GET /articles
# GET /articles.xml
def index
#articles = Article.published.page(params[:page]).per(5).ordered
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #articles }
end
end
# GET /articles/1
# GET /articles/1.xml
def show
#article = Article.find(params[:id])
#comment = Comment.new(:article=>#article)
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/new
# GET /articles/new.xml
def new
#article = Article.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/1/edit
def edit
#article = Article.find(params[:id])
authorize! :edit, #article
end
# POST /articles
# POST /articles.xml
def create
authorize! :create, #article
#article = Article.new(params[:article])
#article.user_id = current_user.id
respond_to do |format|
if #article.save
format.html { redirect_to(#article, :notice => 'Article was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "new" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.xml
def update
#article = Article.find(params[:id])
authorize! :update, #article
respond_to do |format|
if #article.update_attributes(params[:article])
format.html { redirect_to(#article, :notice => 'Article was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.xml
def destroy
#article = Article.find(params[:id])
authorize! :destroy, #article
#article.destroy
respond_to do |format|
format.html { redirect_to(articles_url) }
format.xml { head :ok }
end
end
end
Articles model:
class Article < ActiveRecord::Base
attr_accessible :body, :title, :tag_names
has_many :comments, :dependent => :destroy
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
validates_presence_of :title, :body
validates_uniqueness_of :title
attr_writer :tag_names
after_save :assign_tags
validates_numericality_of :user_id
belongs_to :user
scope :published, lambda {{:conditions => ['published = ?', true]}}
scope :ordered, lambda {{:order => "Created_at DESC" }}
def tag_names
#tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
if #tag_names
self.tags = #tag_names.split(/\,/).map do |name|
Tag.find_or_create_by_name(name)
end
end
end
end
And the form partial used to create the article:
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="field">
<%= f.label :tag_names, "Tags" %>
<%= f.text_field :tag_names %>
</div>
<div class="field">
<%= check_box("article", "published" ) %>
<%= "Publish article" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Any help you can give me on this would be greatly appreciated.
By request:
Ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :Admin
can :manage, :all
can :publish, Article
elsif user.role? :Moderator
can :read, [Article, Comment]
can [:edit, :update], Comment
elsif user.role? :Member
can :read, :all
can :create, [Article, Comment]
can [:edit, :update], Comment
end
end
end
p.s. the only other error I can see (and I don't know if it's relevant or a different issue entirely) is that when trying to view an article (show.html.erb) I receive the following error:
Processing by ArticlesController#show as HTML
Parameters: {"id"=>"1"}
Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT 1 [["id", "1"]]
Completed 500 Internal Server Error in 44ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: article):
app/controllers/articles_controller.rb:18:in `new'
app/controllers/articles_controller.rb:18:in `show'
I'm guessing there's a problem with the authorize! :create, #article line in the ArticleController.create. At the point that that executes, #article isn't created yet.
Judging by the CanCan source, I think the following might do what you want:
def create
authorize! :create, Article
#article = Article.new(params[:article])
#article.user_id = current_user.id
...
The article is not being created because of this.
authorize! :create, #article
You will have to show us your ability model, ability.rb.
You might also want to try the obvious. bundle install and restart the server.
Related
I'm trying to increment new values to an array but the old values get deleted. As you can see in the following, I had one image there and now its NULL, but the new image is there.
SQL (1.5ms) UPDATE "attachments" SET "media_files" = $1, "updated_at" = $2 WHERE "attachments"."id" = $3 [["media_files", "{NULL,image4.jpg}"], ["updated_at", "2018-10-25 09:12:05.564281"], ["id", 11]]
I'm using the carrierwave gem and this is the method I have inside the controller in order to keep the existing values and increment the new ones:
def create
files = #attachment.media_files # copy the old images
files += params[:item][:media_files] # add new file to the files
#attachment.assign_attributes(:media_files => files) # assign back
if #attachment.save
flash[:notice] = "Media files where successfully uploaded"
redirect_back fallback_location: root_path
else
flash[:alert] = "Failed to upload media files"
redirect_back fallback_location: root_path
end
end
And the form is:
<%= form_for #item, url: create_image_path(#attachment), method: :post , :html => {:id => "form"} do |f| %>
<%= f.file_field :media_files, multiple: true %>
<%= f.submit 'Add' %>
<% end %>
Models associations:
class Item < ApplicationRecord
has_many :attachments, dependent: :destroy
accepts_nested_attributes_for :attachments, allow_destroy: true
end
class Attachment < ApplicationRecord
belongs_to :item
mount_uploaders :media_files, AttachmentUploader
validates_presence_of :media_files
end
The schema for the two models:
create_table "attachments", force: :cascade do |t|
t.integer "item_id"
t.integer "account_id"
t.string "media_files", default: [], array: true
t.string "content_type"
t.boolean "success"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.string "title"
t.string "description"
t.integer "category_id"
t.integer "account_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The route for the create method:
post "item/:id/uploads/media_files/:id"=> "attachments#create", :as => :create_image
Any idea what I might be missing here?
You can go with your own code the modification need to done is: -
def create
exitsting_files = #attachment.media_files # copy the old images
new_file = params[:item][:media_files] # new file to the files
new_attachment = Aattachment.new(:media_files => new_file, id: #item.id) #New attachment submitted by form
if new_attachment.save
#push back your exitsting_files along with new one
#attachment.media_files.push(exitsting_files)
#attachment.save
flash[:notice] = "Media files where successfully uploaded"
redirect_back fallback_location: root_path
else
flash[:alert] = "Failed to upload media files"
redirect_back fallback_location: root_path
end
end
However this should be done with nested_atrributes_for concept
<%= form_for #item, url: create_image_path(#attachment), method: :post , :html => {:id => "form"} do |f| %>
<%= f.fields_for : attachments do |ff| %>
<%= ff.file_field :media_files, multiple: true %>
<%end%>
<%= f.submit 'Add' %>
<% end %>
And so on... you can get lots of example for nested form
The user model has a attribute :admin which can be true or false. I want to make a validation so only users with the admin = true can post articles or see the "New article" button in the view.
I am using the devise gem
Controller (articles_controller.rb) :
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /articles
# GET /articles.json
def index
#articles = Article.paginate(page: params[:page], per_page: 4)
end
# GET /articles/1
# GET /articles/1.json
def show
end
# GET /articles/new
def new
#article = current_user.articles.build
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
#article = current_user.articles.build(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: 'Article was successfully created.' }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url, notice: 'Article was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:title, :body)
end
end
Model (article.rb):
class Article < ActiveRecord::Base
belongs_to :user
has_many :comments
validates :title, length: { minimum: 5 }
validates :title, uniqueness: true, uniqueness: { message: "This article title has already been posted."}
validates :body, length: { minimum: 15 }
end
Model (user.rb):
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_uniqueness_of :username
has_many :articles
has_many :comments
end
Schema :
ActiveRecord::Schema.define(version: 20160320222854) do
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "comments", force: :cascade do |t|
t.text "body"
t.integer "user_id"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["article_id"], name: "index_comments_on_article_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "contacts", force: :cascade do |t|
t.string "name"
t.string "email"
t.text "message"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: :cascade do |t|
t.string "username", default: "", null: false
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: false
t.string "firstname"
t.string "lastname"
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
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
view /articles (index.html.erb):
<div class="row">
<!-- Blog article Content Column -->
<div class="col-lg-8">
<% #articles.each do |article| %>
<!-- Blog article -->
<!-- Title -->
<h4 style="font-size: 45.5px;"><%= link_to article.title, article %></h4>
<!-- Date/Time -->
<p><span class="glyphicon glyphicon-time"></span>
<%= time_ago_in_words(article.created_at) %>
</p>
<!-- Author -->
<p>
Article By:<strong> <%= article.user.username %></strong>
</p>
<hr>
<% end %>
<%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" %>
</div>
<!-- paginate -->
<%= will_paginate #articles %>
<br />
Thanks in advance to all the wonderful people here willing to lend a helping hand.
You can add a filter method in Application Controller
def admin_access
render(text: 'Unauthorised') and return unless current_user.admin
end
And use this in Atricles controller or any other place where it is required
before_filter :admin_access, only: [:new, :create, :edit, :update, :destroy]
And in the views, check if user is admin
<% if current_user.admin %>
# new/edit/delete links
<% end %>
Even though, not showing the link in the view solves the problem, It is always better to have proper authorisation logic in the server side.
in the controller
def new
if current_user.admin
#article = current_user.articles.build
else
redirect_to root_path and return #somewhere you want to redirect
end
end
in the view
<% if current_user.admin %>
<%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" %>
<% end %>
To Show the New Article link to the only Admin. Add condition to your link_to tag. This will only hide the link.
<%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" if current_user.admin? %>
Suppose if you want Admin Users only create a New Article. Then you need to implement authorization in your application. Try cancancan gem
For the docs and video
i am new to rails so any help would be much appreciated. I have the models userrs (recruiters) and adverts. Userr has_many adverts and Advert belongs to a user.
Question: when a userr creates an advert i want the created advert to
be automatically linked to the userr that created the advert. I am
unsure how to go about this in the controller
i know how to assign an advert to a user in the console. but unsure how to do this in the controller
console
advert = Advert.first
advert.userr_id = 3
advert.save
route
Rails.application.routes.draw do
resources :adverts
resources :feedbacks
devise_for :userrs
devise_for :userjs
root 'static_pages#homepg'
get 'affiliate', to: 'static_pages#affiliatepg'
get 'terms', to: 'static_pages#termpg'
get 'privacy', to: 'static_pages#privacypg'
get 'contact', to: 'static_pages#contactpg'
get 'about', to: 'static_pages#aboutpg'
get 'recruiters', to: 'static_pages#recruiterpg'
get 'jobseekers', to: 'static_pages#jobseekerpg'
get 'approach', to: 'static_pages#approachpg'
get 'sector', to: 'static_pages#sectorpg'
get 'news', to: 'static_pages#newspg'
get 'offer', to: 'static_pages#offerpg'
get 'refferal', to: 'static_pages#refferalpg'
end
i placed the below code:
in my advert controller under the create function:
def create
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build(params[:advert])
if #advert.save
flash[:notice] = 'Successfully created advert'
redirect_to recruiters_path
else
render action: 'new'
end
end
but i got the error:
Couldn't find Userr without an ID
log - error message
Started GET "/adverts/new" for 127.0.0.1 at 2015-04-02 14:59:38 +0100
Processing by AdvertsController#new as HTML
Completed 404 Not Found in 1ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Userr without an ID):
app/controllers/adverts_controller.rb:20:in `new'
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_source.erb (8.2ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_trace.html.erb (3.4ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_request_and_response.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_web_console.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/diagnostics.html.erb within rescues/layout (27.3ms)
Started GET "/adverts/new" for 127.0.0.1 at 2015-04-02 14:59:38 +0100
Processing by AdvertsController#new as HTML
Completed 404 Not Found in 1ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Userr without an ID):
app/controllers/adverts_controller.rb:20:in `new'
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_source.erb (8.1ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_trace.html.erb (3.0ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_web_console.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/diagnostics.html.erb within rescues/layout (26.2ms)
Schema
ActiveRecord::Schema.define(version: 20150330233948) do
create_table "adverts", force: true do |t|
t.string "title"
t.text "content"
t.integer "category_jobtype_id"
t.integer "category_positiontype_id"
t.integer "salarystart"
t.integer "salaryend"
t.integer "category_country_id"
t.string "city"
t.string "town"
t.string "postcode"
t.integer "category_editorialapproval_id"
t.integer "category_applicationrequest_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "userr_id"
end
create_table "userrs", force: true 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"
t.datetime "updated_at"
t.string "firstname"
t.string "lastname"
t.string "companyname"
t.integer "category_businesstype_id"
end
add_index "userrs", ["email"], name: "index_userrs_on_email", unique: true
add_index "userrs", ["reset_password_token"], name: "index_userrs_on_reset_password_token", unique: true
model
class Advert < ActiveRecord::Base
belongs_to :user
end
class Userr < ActiveRecord::Base
has_many :adverts
end
controller: Advert
class AdvertsController < ApplicationController
respond_to :html, :xml, :json
before_action :set_advert, only: [:show, :edit, :update, :destroy]
def index
#adverts = Advert.all
respond_with(#adverts)
end
def show
respond_with(#advert)
end
# def new
# #advert = Advert.new
# respond_with(#advert)
# end
def new
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build
respond_with(#advert)
end
def edit
end
# def create
# #advert = Advert.new(advert_params)
# #advert.save
# respond_with(#advert)
# end
def create
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build(params[:advert])
if #advert.save
flash[:notice] = 'Successfully created advert'
redirect_to recruiters_path
else
render action: 'new'
end
end
def update
#advert.update(advert_params)
respond_with(#advert)
end
def destroy
#advert.destroy
respond_with(#advert)
end
private
def set_advert
#advert = Advert.find(params[:id])
end
def advert_params
params.require(:advert).permit(:title, :content, :category_jobtype_id, :category_positiontype_id, :salarystart, :salaryend, :category_country_id, :city, :town, :postcode, :category_editorialapproval_id, :category_applicationrequest_id)
end
end
form for advert
<%= simple_form_for(#advert) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :title %>
<%= f.input :content %>
<%= f.association :category_jobtype, collection: CategoryJobtype.all, prompt: "select a category" %>
<%= f.association :category_positiontype, collection: CategoryPositiontype.all, prompt: "select a category" %>
<%= f.input :salarystart %>
<%= f.input :salaryend %>
<%= f.association :category_country, collection: CategoryCountry.all, prompt: "select a category" %>
<%= f.input :city %>
<%= f.input :town %>
<%= f.input :postcode %>
<%= f.association :category_editorialapproval, as: :radio_buttons %>
<%= f.association :category_applicationrequest, as: :radio_buttons %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
any help will be appreciated
First, you need to add userr_id to params:
def advert_params
params.require(:advert).permit(:userr_id, :title, :content, :category_jobtype_id, :category_positiontype_id, :salarystart, :salaryend, :category_country_id, :city, :town, :postcode, :category_editorialapproval_id, :category_applicationrequest_id)
end
Second, add userr_id to the form:
<%= simple_form_for(#advert) do |f| %>
<%= f.hidden_field(:userr_id) %>
Third, change the param name in create:
def create
#userr = Userr.find(params[:advert][:userr_id])
You can do the same via routes, without altering the form. It's much cleaner but needs more source changes. I can't give you the full syntax here, but it will look like the following:
#routes.rb
resources :userrs do
resources :addverts
end
And the advert's form will become /userrs/[user-id]/adverts, so you'll be able to get the user id from the url instead of the form field. But you'll need to change all the path shortcuts.
Been stuck on this all afternoon/evening. Would really appreciate the help as I continue to work on this.
I have two different tables. Posts (status and photo) and Places (address). I'd like to combine these (status, photo, address) into one form and one show.
So, I think I am having trouble making an Active Record Query Interface. However, I may have messed up in Associating the tables...
Post.rb Model
class Post < ActiveRecord::Base
belongs_to :place
belongs_to :user
has_many :comments
has_many :commenters, through: :comments, source: :user
end
Place.rb Model
class Place < ActiveRecord::Base
has_many :posts
end
Posts _form.html.erb
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :status %><br>
<%= f.text_field :status %>
</div>
<div class="field">
<%= f.label :upload %><br>
<%= f.text_field :upload %>
</div>
<%= f.label :place %><br>
<%= f.text_field :place %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Posts show.html.erb
<h1><%= #post.status %></h1>
<p><%= link_to #post.upload, #post.upload %></p>
<p><%= #post.place %></p>
<%= form_for [#post, #comment] do |f| %>
<p>
<%= f.text_area :response, placeholder: "Add a comment...", :rows => 8, :cols => 40 %>
</p>
<%= f.submit %>
<% end %>
<ul class="comments">
<% #post.comments.each do |comment| %>
<li><%= "#{comment.user.try(:email)} posted: #{comment.response}" %></li>
<% end %>
</ul>
<p><%= link_to "Back to home page", root_path %></p>
posts_controller.rb
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
#post = Post.find params[:id]
#comment = Comment.new(:post => #post)
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
def create
safe_post = params.require(:post).permit(:status, :upload)
#post = current_user.posts.new safe_post
#post.place = Place.from_params params[:place]
#post.save
redirect_to #post
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(:status, :upload)
end
end
places_controller.rb
class PlacesController < ApplicationController
before_action :set_place, only: [:show, :edit, :update, :destroy]
# GET /places
# GET /places.json
def index
#places = Place.all
end
# GET /places/1
# GET /places/1.json
def show
#place = Place.find params[:id]
end
# GET /places/new
def new
#place = Place.new
end
# GET /places/1/edit
def edit
end
# POST /places
# POST /places.json
def create
#place = Place.new(place_params)
respond_to do |format|
if #place.save
format.html { redirect_to #place, notice: 'Place was successfully created.' }
format.json { render action: 'show', status: :created, location: #place }
else
format.html { render action: 'new' }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /places/1
# PATCH/PUT /places/1.json
def update
respond_to do |format|
if #place.update(place_params)
format.html { redirect_to #place, notice: 'Place was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# DELETE /places/1
# DELETE /places/1.json
def destroy
#place.destroy
respond_to do |format|
format.html { redirect_to places_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_place
#place = Place.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def place_params
params.require(:place).permit(:address, :latitude, :longitude)
end
end
schema.rb
ActiveRecord::Schema.define(version: 20140324213459) do
create_table "comments", force: true do |t|
t.integer "user_id"
t.integer "post_id"
t.string "response"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "places", force: true do |t|
t.string "address"
t.float "latitude"
t.float "longitude"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "posts", force: true do |t|
t.string "status"
t.string "upload"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "place_id"
end
add_index "posts", ["place_id"], name: "index_posts_on_place_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
create_table "users", force: true do |t|
t.string "name"
t.string "photo"
t.string "bio"
t.datetime "created_at"
t.datetime "updated_at"
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"
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
routes.rb
DondeApp::Application.routes.draw do
resources :posts do
resources :comments, only: :create
resources :places
end
devise_for :users
root 'posts#index'
end
you need nested model form, look up this http://railscasts.com/episodes/196-nested-model-form-part-1
You seem to try to access #post.place in your _form.html.erb which might actually work through AREL magic, but you will probably get some strange results putting it into a text_field. Usually you would use a select box to select from existing places or whip up a jQuery control to find the right reference.
So the query in your show action should actually work to produce a suitable Post object, given it was set up correctly in the create action. You do have some code in there using Place.from_params to create a new place using a mysterious params[:place] that does not seem to be permitted (for the Post object that is). As your form only contains a text_field to refer to the place I have my doubts that this will work.
Check out your Post objects in the rails console and see wether the refer to a valid Place object. If they do you have to reflect this in your view, accessing the place attribute of your #post object will return a whole object which does not "know" how to present itself in a text_field, much less to create itself from one.
I guess this is the main problem you are having, but it is difficult to tell if you do not tell us what you expect and what you get instead.
Given this, you could optimize your AREL-queries to use includes(:place) in order to avoid the n+1 queries problem, but that would just apply to your index action. Otherwise I think AREL has you mostly covered.
When I submit the form, the data is not being sent in the post and set via parameters. I can't for the life of me figure out why. This form is in the plan/show action, so that's why you see me setting the #action variable there. It is sent via JS.
routes.rb
resources :plans do
resources :actions
end
action.rb
belongs_to :plan
plan.rb
has_many :actions
plans_controller.rb
def show
#plan = current_user.plans.includes(:actions).find(params[:id])
#action = Action.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #plan }
end
end
actions_controller.rb
before_filter :get_plan
def create
#action = #plan.actions.new(params[:action])
#action.user_id = current_user.id
#action.save
end
private
def get_plan
#plan = current_user.plans.find(params[:plan_id])
end
create.js.erb in views/actions folder
$('div#actions').prepend("<%= escape_javascript(render #action) %>");
$('div#<%= dom_id(#action) %>').effect('highlight');
_form.html.erb partial
<%= form_for ([#plan, #action]), remote: true do |f| %>
<%= f.text_field :desc %>
<%= f.number_field :days %>
<%= f.submit %>
<% end %>
parameters sent via POST (missing action hash - why??)
Started POST "/plans/1/actions"
Parameters: {"utf8"=>"✓", "authenticity_token"=>"**removed**", "commit"=>"Create Action", "plan_id"=>"1"}
DB Schema
create_table "plans", :force => true do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "actions", :force => true do |t|
t.string "desc"
t.integer "plan_id"
t.integer "days"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
Action is a reserved word. If you call it anything else (except controller, which is also reserved) then it will work.
http://guides.rubyonrails.org/action_controller_overview.html#routing-parameters
The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values.