Ive installed geocoder gem but when i type the address in the form it doesnt save any params in the table, its just an empty object. is there something im missing?
The location model:
class Location < ApplicationRecord
attr_accessor :postcode, :longitude, :latitude
geocoded_by :postcode
after_validation :geocode, :if => :postcode_changed?
end
The location controller:
def create
#location = Location.new(location_params)
if #location.save
redirect_to message_path(current_user.id)
flash[:success] = "Success"
else
redirect_to root_path
flash[:danger] = "failed"
end
end
private
def location_params
params.require(:location).permit(:postcode, :user_id)
end
Here is the form:
<%= form_for #location, :url => locations_path do |f| %>
<p>
<%= f.label "postcode" %><br />
<%= f.text_field :postcode %>
<%= f.hidden_field :user_id, :value => current_user.id %>
</p>
<p><%= f.submit %></p>
<% end %>
And here is my schema:
create_table "locations", force: :cascade do |t|
t.string "postcode"
t.float "longitude"
t.float "latitude"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_locations_on_user_id"
end
So the idea is that a user would enter his postcode in the form on his profile page his location would show for all the other users to see.
I may not have grasped the concept of it so any help or guidance would be much appreciated. Thanks
Oh and here is the table entry after save:
irb(main):011:0> Location.last
Location Load (0.4ms) SELECT "locations".* FROM "locations" ORDER BY "locations"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<Location id: 10, postcode: nil, longitude: nil, latitude: nil,
user_id: 9, created_at: "2017-10-17 09:40:43", updated_at: "2017-10-17 09:40:43">
Related
I have a User who has a Profile (2 models). Here is the relevant part of my schema:
create_table "profiles", force: :cascade do |t|
t.text "about"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "provider"
t.string "uid"
t.string "first_name"
t.string "last_name"
t.string "street"
t.integer "house_number"
t.string "city"
t.integer "zip_code"
t.string "image"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
The reason I have a Profile as a separate model, as because I thought it was easier to assign roles later, for certain manipulations. So, now I am wondering, if it is possible to ask for
user.first_name , user.last_name, user.email and user.password
in the registration form and for
user.street, user.house_number, user.city and user.zip_code
in the Profile#new _form. Like this:
<%= form_for([#user, #profile], url: user_profiles_path, method: :post) do |form| %>
<div class="field">
<%= form.label :about %>
<%= form.text_area :about %>
</div>
<div class="field">
<%= form.file_field :avatar %>
<% form.label "Profile photo" %>
</div>
<div class="field">
<%= form.label :street %><br />
<%= form.text_field :street, class: 'form-control' %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
So here you can see, that avatar and about refer to a Profile, while street if from User table. But somehow this form, doesn't undertand this. I allow nested_attributes for :profile, but I guess, this doesn't matter for this form. I know, that maybe the easier way would be, to rearrange my table, so that all the adress attributes are stored in Profile. But as I am new to Rails and I really wish to learn more, I would love to know, if there is a way of saving to both #user and #profile in one form? Thank you!
You're touching on two somewhat different concepts here that most beginners get stumped on.
The first is nested resources. A nested resource has its path nested under another resource.
# config/routes.rb
resources :magazines do
resources :ads
end
So now instead of /ads we have /magazines/:magazine_id/ads. So the routes themselves describe the relation between the two resources in a RESTful way - awesome.
class AdsController < ApplicationController
before_action :set_magazine
# GET /magazines/:magazine_id/ads/new
def new
#ad = #magazine.ads.new
end
# POST /magazines/:magazine_id/ads/new
def create
#ad = #magazine.ads.new(ad_params)
if #ad.save
redirect_to #ad
else
render :new
end
end
def set_magazine
#magazine = Magazine.find(params[:magazine_id])
end
# ...
end
<%= form_for([#ad, #magazine]) do |f| >
# ...
<% end %>
This will let you create ads that belong to a magazine. It will not magically let you create a magazine at the same time as an add in the same form.
That's where nested attributes comes in. It creates a super-powered setter in the model which lets it accept attributes for an associated model and creates / updates the associated records in the same request as the parent.
This for example would let us create a user and a profile in the same form:
class User < ApplicationRecord
has_one :profile
accepts_nested_attributes_for :profile
end
class Profile < ApplicationRecord
belongs_to :user
end
<%= form_for(#user) do |f|>
<div class="field">
<%= f.label :email %>
<%= f.email_field :street, class: 'form-control' %>
</div>
# ...
<%= f.fields_for(:profile) do |profile_fields| %>
<div class="field">
<%= profile_fields.label :about %>
<%= profile_fields.text_area :about %>
</div>
<% end %>
# ...
<% end %>
class UsersController < ApplicationRecord
POST /users
def create
#user = User.new(user_params)
if #user.save
redirect_to :user
else
render :new
end
end
# ...
private
def user_params
params.require(:user)
.permit(:email, ..., profile_attributes: [:about])
end
end
accepts_nested_attributes_for is one of the most misused, misunderstood and hardest concepts to grasp in rails though. If you're just starting out you should consider bypassing this and circling back around once you have a better understanding of rails.
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
I want to add the date in rails form. For example
def create
#land=current_user.lands.build(land_params)
if #land.save
session[:land_id]=#land.id
flash[:success]="Success"
redirect_to lands_path
else
flash[:error]="Fail!!"
render 'new'
end
end
schema.rb
create_table "lands", force: :cascade do |t|
t.date "DateStart"
t.date "DateEnd"
end
new.html.erb
<%= form_for #land do |f| %>
<p>Information</p>
<%= f.label :Start %><br />
<%= f.date_select :DateStart, :default => #DateStart, :order => [:month, :day, :year] %>
<%= f.label :End %><br />
<%= f.date_select :DateEnd,:default => #DateEnd,:order => [:month, :day, :year]%>
<% end %>
show.html.erb
<p>Start : <%= #land.DateEnd %></p>
<p>End : <%= #land.DateEnd %></p>
Land.controller
def show
#land= Land.find(params[:id])
end
But nothing is printed out in my show.html.erb. When I check database my DateStart and DateEnd is nil. I don't know what wrong. Can you give me some advice? Thanks
You can follow like below
def create
#land= Land.new(land_params)
#land.user = current_user
if #land.save
flash[:success] = 'Land was successfully created.'
redirect_to lands_path #=> or anything
else
flash[:error] = 'Land was not created successfully .'
redirect_to lands_path #=> or anything
end
end
I think that's work
You make sure add this before_action :authenticate_user! on your controller header, that's cannot access user without authentication
Hope to help
You can follow my answers -
Method - 1. No association with User and Land model.
lands_controller.rb file look like -
class LandsController < ApplicationController
def new
#DateStart = Date.today
#DateEnd = Date.today + 2.days
#land = Land.new
end
def create
#land = Land.new(land_params)
if #land.save
session[:land_id] = #land.id
flash[:success]= "Success"
redirect_to lands_path
else
flash[:error] = "Fail!!"
render 'new'
end
end
def show
#land= Land.find(params[:id])
end
def land_params
params.require(:land).permit(:DateStart, :DateEnd)
end
end
Database Schema file look like - (schema.rb)
create_table "lands", force: :cascade do |t|
t.date "DateStart"
t.date "DateEnd"
end
Lands controller new action view file - (app/views/lands/new.html.erb)
<%= form_for #land do |f| %>
<p>Information</p>
<%= f.label :Start %><br />
<%= f.date_select :DateStart, :default => #DateStart, :order => [:month, :day, :year] %>
<%= f.label :End %><br />
<%= f.date_select :DateEnd,:default => #DateEnd,:order => [:month, :day, :year]%>
<%= f.submit "Submit" %>
<% end %>
Lands view page (app/views/lands/show.html.erb)
<p>Start : <%= #land.DateEnd %></p>
<p>End : <%= #land.DateEnd %></p>
Method - 2. Association with User and Land model.
lands_controller.rb file look like - (app/controllers/lands_controller.rb)
class LandsController < ApplicationController
before_action :authenticate_user!
def new
#DateStart = Date.today
#DateEnd = Date.today + 2.days
#land = current_user.lands.build
end
def create
#land = current_user.lands.build(land_params)
if #land.save
session[:land_id] = #land.id
flash[:success]= "Success"
redirect_to lands_path
else
flash[:error] = "Fail!!"
render 'new'
end
end
def show
#land= Land.find(params[:id])
end
def land_params
params.require(:land).permit(:DateStart, :DateEnd)
end
end
Database Schema file look like - (schema.rb)
create_table "lands", force: :cascade do |t|
t.date "DateStart"
t.date "DateEnd"
t.index ["user_id"], name: "index_rooms_on_user_id"
end
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
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
User model look like - (app/models/user.rb)
class User < ApplicationRecord
has_many :lands
end
Land model look like - (app/models/land.rb)
class Land < ApplicationRecord
belongs_to :user
end
Lands controller new action view file - (app/views/lands/new.html.erb)
<%= form_for #land do |f| %>
<p>Information</p>
<%= f.label :Start %><br />
<%= f.date_select :DateStart, :default => #DateStart, :order => [:month, :day, :year] %>
<%= f.label :End %><br />
<%= f.date_select :DateEnd,:default => #DateEnd,:order => [:month, :day, :year]%>
<%= f.submit "Submit" %>
<% end %>
Lands view page (app/views/lands/show.html.erb)
<p>Start : <%= #land.DateEnd %></p>
<p>End : <%= #land.DateEnd %></p>
I hope it should work.
I have two models: User and WritingSample. A user can have many writing samples. I have a page with a form with extra JS for adding additional writing sample fields -- however, I've disabled this for the time being and I'm trying to get it working with just the one.
What I want to happen: the user types the url of a writing sample into the form and this is stored as a WritingSample row.
The form seems to be working. But I'm clearly not doing something right.
When I submit the form, I can see that safe_params contains:
"writing_samples_attributes"=><ActionController::Parameters {"0"=><ActionController::Parameters {"url"=>"foo"} permitted: true>}
But it looks like User wants an id:
> User
User(id: integer, name: string, writing_sample_id: integer)
User.new(safe_params) returns:
<User id: nil, name: "joe", created_at: nil, updated_at: nil, writing_sample_id: nil>
The new user isn't created, and I get the error:
user.errors.first
[:"writing_samples.user", "must exist"]
What steps do I need to take to store the submitted data in the :url field?
WritingSample:
class WritingSample < ApplicationRecord
belongs_to :user
end
User:
class User < ApplicationRecord
has_many :writing_samples
accepts_nested_attributes_for :writing_samples
end
Schema:
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "writing_sample_id"
t.index ["writing_sample_id"], name: "index_users_on_writing_sample_id"
end
create_table "writing_samples", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "url"
t.index ["user_id"], name: "index_writing_samples_on_user_id"
end
My controller:
def create
user = User.new(safe_params)
byebug
if user.save
redirect_to '/thanks'
else
byebug
redirect_to new_creator_path
end
end
private
def safe_params
params.require(:user).permit(:name, :writing_samples_attributes => [:url])
end
The form:
<%= form_for(#user, url: creators_path) do |f| %>
<%= f.label :name %>
<%= f.label 'Writing samples' %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.fields_for :writing_samples do |sample_f| %>
<%= sample_f.text_field :url %>
<% end %>
<% end %>
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.