ROR: undefined method ` ' for nil:NilClass - ruby-on-rails

Environment: Rails 3.0.1, MySQLI have a Users table, and I want to search for users by city.
I have the following code in users_controller:
def output
#results = User.select(:fname, :lname).where(['city = ?', params[:text1]]).all
output.html.erb in View:
<% #results.each do |r| %>
<%= #r.fname %>
<%= #r.lname %>
<% end %>
It will show up as undefined method `fname' for nil:NilClass.
However, if I type following in View, it works:
your search are <%= #results %>
The output is:
your search are [#<User fname: "adam", lname: "huang">, #<User fname: "eric", lname: "huang">]
The Users table is:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.integer :uid
t.string :email
t.string :password
t.string :fname
t.string :lname
t.string :city
t.integer :pid
t.timestamps
end
end

Try this
<% #results.each do |r| %>
<%= r.fname %>
<%= r.lname %>
<% end %>
It looks like you did a simple typo.

Related

Undefined method `street' for #<Profile:0x00007fea78589ac0>

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.

Cant add date in rails 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.

undefined method `image' for #<Array> when using group_by

Hi can anyone point me to the right direction? I´m trying to show images on views/pages/index.html.erb the images are uploaded on views/products/new.html.erbthrough the _form.html.erbpartial. Each product/picture then belongs to a category which I can select in the _navbar.html.erb and is then directed to the views/categories/show.html.erbto see pictures of each product in that category and so on.
That is all working fine
But now I want to display the last added picture in each category on the views/pages/index.html.erb and I´m always getting this error : undefined method 'image' for #<Array:0x007f8d1fb19ff0>
I´m pretty lost at the moment, and hopefully someone can guide me to the right path.
My code id like this:
pages_controller.rb
class PagesController < ApplicationController
def index
#products = Product.all.order(created_at: :desc).group_by(&:category_id)
end
def about
end
def location
end
def stockists
end
end
views/pages/index.html.erb
<% #products.each do |product| %>
<div class="col-lg-3 col-sm-6 col-xs-12 center-block " >
<%= image_tag product.image.url(:medium) %>
<p><%= product.name %></p>
<p><%= product.category.name %></p>
<% end %>
</div>
And then I have, the products.rb and category.rb
product.rb
class Product < ActiveRecord::Base
mount_uploader :image, ImageUploader
validates_presence_of :name, :price
validates_numericality_of :price
belongs_to :category
end
category.rb
class Category < ActiveRecord::Base
has_many :products
end
this as part of the schema.rb
create_table "products", force: :cascade do |t|
t.string "name"
t.string "description"
t.float "price"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id", default: 1
end
add_index "products", ["category_id"], name: "index_products_on_category_id", using: :btree
and in the end there is this part
add_foreign_key "order_items", "orders", on_delete: :cascade
add_foreign_key "order_items", "products"
add_foreign_key "orders", "users", on_delete: :cascade
add_foreign_key "products", "categories"
end
You are using group_by in the controller, an enumerable method that returns a hash of Product arrays keyed by category_id.
#product = {
:category1 => [#<Product category_id=1>, #<Product category_id=1>, ...],
:category2 => [#<Product category_id=2>, #<Product category_id=2>, ...]
}
When you loop through #products in the view, you are looping through a hash where each iteration is passing an array.
The product variable does not contain a product, but an array of products.
<% #products.each do |product| %> # product is type Array!
<%= image_tag product.image.url(:medium) %> # Array.image throws an error!
<% end %>
You must create an outer loop to step through the hash.
<% #products.each do |category, products| %>
<% products.each do |product| %>
# do stuff
<% end %>
<% end %>

how to add a record to the linked table?

please help solve the problem.
models:
class Tag < ActiveRecord::Base
has_and_belongs_to_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :tags
end
tables:
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
t.integer "user_id"
end
create_table "posts_tags", id: false, force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
end
create_table "tags", force: :cascade do |t|
t.string "tagname"
end
form:
<%= form_for [#user, #post] do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :body %>
<%= f.text_area :body %>
<label class="lbl_tagname"><%=t :tags %></label>
<%= text_field_tag 'tagnames', nil, class: 'tagnames' %>
<%= f.submit %>
<% end %>
post controller:
def new
#user = User.find(params[:user_id])
#post = Post.new
end
def create
#post = current_user.posts.build(post_params)
if #post.save
add_new_tags(#post)
flash[:success] = t :post_saved
redirect_to user_post_path(#current_user, #post)
else
flash.now[:error] = t :post_not_saved
render 'new'
end
end
private
def add_new_tags(post)
tagnames = params[:tagnames].split(/[, \.?!]+/)
tagnames.each do |tagname|
tagname_exist = Tag.find_by tagname: tagname.downcase
tag = Tag.create(tagname: tagname.downcase) if !tagname_exist
tag.posts.push post
p '=============='
p post.id
p '=============='
end
end
def post_params
params.require(:post).permit(:title, :body, :tagnames)
end
a user visits a page, see the form. fill in the form below. sends. resulting record is not added to the table posts_tags.
displays the following error message:
NoMethodError in PostsController#create
undefined method `posts' for nil:NilClass
the console displays the following:
"=============="
391
"=============="
Tag Load (0.1ms) SELECT "tags".* FROM "tags" WHERE "tags"."tagname" = ? LIMIT 1 [["tagname", "asd"]]
Completed 500 Internal Server Error in 904ms (ActiveRecord: 811.8ms)
NoMethodError (undefined method `posts' for nil:NilClass):
app/controllers/posts_controller.rb:93:in `block in add_new_tags'
app/controllers/posts_controller.rb:89:in `each'
app/controllers/posts_controller.rb:89:in `add_new_tags'
app/controllers/posts_controller.rb:45:in `create'
wherein. in table post entry is created
def add_new_tags(post)
tagnames = params[:tagnames].split(/[, \.?!]+/)
tagnames.each do |tagname|
tag = Tag.find_or_create_by(tagname: tagname.downcase)
tag.posts << post
end
end
You need to push post to tag only after initilizing tag variable
tag = tagname_exist || Tag.create(tagname: tagname.downcase)
tag.posts.push post

Ruby Rails update two different table columns using form

Here is my newbie story,
my table looks like this:
create_table "books", :force => true do |t|
t.string "title"
t.integer "count"
t.integer "id"
end
create_table "users", :force => true do |t|
t.string "name"
t.decimal "money"
end
user can create many books, and user using these forms to update it:
to update money:
<%= form_for(#user) do |f| %>
<%= f.number_field :money, :value => #user.money %>
<% end %>
to update book title, count etc., for each books:
<% #book.each do |book| %>
<%= form_for(book) do |f| %>
<%= f.number_field :count %>
<%= f.text_field :title %>
<% end %>
<% end %>
and im trying to do is i want update both of them. (lets say user need to update money and book title) currently it only able to update money or book info separately
model:
class Book < ActiveRecord::Base
attr_accessible :count, :title, :id
belongs_to :user
end
any idea? Thanks!
It's not that simple to explain in a single answer. I suggest you to have a look at the following Railscasts to get an idea.
http://railscasts.com/episodes/198-edit-multiple-individually
http://railscasts.com/episodes/165-edit-multiple-revised

Resources