how to resolve NoMethodError in ContactsController#index in ROR-4 - ruby

Please help me to resolve this error and reedit my all pages. Actually i am new to Ruby on Rails and i am using rails version-4 and ruby version-1.9.3.I want to show one form including select options and selected value saved in DB. My errors and code snippets explained below.
Error:
undefined method `email_providers=' for #<Class:0x4e68df0>
Extracted source (around line #2):
1 class Contact < ActiveRecord::Base
2 self.email_providers = %w[Gmail Yahoo MSN]
3 validates :email_provider, :inclusion => email_providers
4 end
views/contacts/index.html.erb
<%= form_for #contact,:url => {:action => "create"} do |f|%>
<%= f.text_field:gmail %>
<%= f.select :email_provider, options_for_select(Contact.email_providers, #contact.email_provider) %>
<%= f.submit "Submit"%>
<% end %>
controller/contacts_controller.rb
class ContactsController < ApplicationController
def index
#contact=Contact.new
end
def create
end
end
models/contact.rb
class Contact < ActiveRecord::Base
self.email_providers = %w[Gmail Yahoo MSN]
validates :email_provider, :inclusion => email_providers
end
migrate/20141222061313_create_contacts.rb
class CreateContacts < ActiveRecord::Migration
def change
create_table :contacts do |t|
t.string :gmail
t.string :yahoo
t.string :msn
t.timestamps
end
end
end
I want to show the 3 content(gmail,yahoo,msn) in option drop down list and while it will be selected and clicked on submit button it will be saved in DB.Please help me to edit the code.Thanks in advance..

Change
self.email_providers = %w[Gmail Yahoo MSN]
validates :email_provider, :inclusion => email_providers
in your Contact model class to:
EMAIL_PROVIDERS = %w{Gmail Yahoo MSN}
validates :email_provider, inclusion: {in: EMAIL_PROVIDERS}
and the error should be fixed.
As you can guess, your Contact class doesn't have a self.email_providers= method. So trying to assign a value to it through this method will crash. What I've done is created a constant that can be easily accessed within the class through EMAIL_PROVIDERS and outside the class through Contact::EMAIL_PROVIDERS

Related

Saving associated many to many relation in Rails

I looked at related posts but could not get my code working. I have device and project models which are connected thru projects_devices table. My models look like this:
class Device < ActiveRecord::Base
has_many :projects, :through => :projects_devices
has_many :projects_devices
accepts_nested_attributes_for :projects_devices, allow_destroy: true
end
class Project < ActiveRecord::Base
has_many :devices, :through => :projects_devices
has_many :projects_devices
accepts_nested_attributes_for :projects_devices
end
class ProjectsDevice < ActiveRecord::Base
belongs_to :device
belongs_to :project
end
my device controller:
def new
#device = Device.new
project_device = #device.projects_devices.build
#projects = Project.all
end
def create
#device = Device.create(device_params)
end
and my device_param :
def device_params
params.require(:device).permit(:name, :projects_devices_attributes => [:id , project_id: []])
end
My view:
<%= f.label :Projects_devices %><br>
<%= f.fields_for :projects_devices do |proj| %>
<%= proj.select(:project_id, [], {}, {class: "form-control projects-devices", multiple: "multiple" } ) do %>
<% if (#projects) %>
<% for #project in #projects %>
<%= content_tag(:option, #project.name, value: #project.id) %>
<% end %>
<% end %>
<% end %>
<% end %>
I have a many to many association between two models. While creating and editing devices, I should be able to list all the projects available. And select only the ones required. When I save, the projects_devices table should be updated.
I have multiple problems here:
When I save a new device,
a. the projects_devices table has only device_id but not project_id. project_id is null
b. if there are 2 projects and I select only one, even then, two association records are created with only device_id (as mentioned above, project_id is missing). It should create only one association.
When a new device is edited,
a. Project list, list of all projects is empty.
b. I see 2 select boxes are displayed instead of one for projects(there are 2 projects currently).
c. updating the device is not happening.
I checked the params:
"device"=>{"name"=>"ABC",
"projects_devices_attributes"=>{"0"=>{"project_id"=>["",
"298486374"]}}},
"commit"=>"Create Device"}
My rails log shows that my application is inserting only device_id:
SQL (0.1ms) INSERT INTO `projects_devices` (`device_id`) VALUES (980190994)
Can somebody help me figure out the problem
Im not sure, but try this params.
Maybe it helps. :)
def device_params
params.require(:device).permit(:name, :projects_devices_attributes =>[:id, :device_id, :project_id, :_destroy])
end

Assign categories to a newly created post with Ruby and Padrino

I'm working on my ligthweight Padrino CMS which very much resembles the functionalities of Wordpress. When creating a new post I want to be able to assign them to many of the existing categories. Somehow I can not get my form work.
My models look like that:
Post model
class Post < ActiveRecord::Base
belongs_to :account
has_many :categorizations
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categories
end
Category model
class Category < ActiveRecord::Base
has_many :categorizations
has_many :posts, :through => :categorizations
belongs_to :category
end
Categorization model
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
end
I have also created a migration for the joint table
class CreateCategorizations < ActiveRecord::Migration
def self.up
create_table :categorizations do |t|
t.integer :category_id
t.integer :post_id
t.timestamps
end
end
def self.down
drop_table :categorizations
end
end
And here is the related part of the form
<% fields_for :categories do |c| %>
<fieldset class='control-group <%= error ? 'has-error' : ''%>'>
<%= c.label 'Category title', :class => 'control-label' %>
<div class='controls'>
<%= c.select(:id, :collection => #categories, :fields => [:title, :id], :include_blank => true, :multiple => true, :class => 'form-control input-xlarge input-with-feedback') %>
<span class='help-inline'><%= error ? c.error_message_on(:id) : "Select a category if there is a parent category" %></span>
</div>
</fieldset>
<% end %>
I don't know what I'm missing but the association is not created. I do not mention categories in the controller during the creation but I do fill up the dropdown with the existing Categories. Somehow I would like to associate them to the new post.
I will greatly appreciate if someone can point me to the right direction with this. The error I get is this:
NoMethodError at /admin/posts/create
undefined method `each' for nil:NilClass
file: collection_association.rb location: replace line: 383
The forms POST data contains that:
POST
Variable authenticity_token
Value "c760c21a5d1f85bfc19e179b37d56f67"
category_active_record_relation {"id"=>["2", "3"]}
post
{"post_name"=>"Test post", "post_type"=>"blogpost", "post_title"=>"Postie", "slug"=>"This is a custom set slug", "post_date"=>"2015-06-30", "post_content"=>"Lorem ipsum dolor sit amet consequtiv", "post_excerpt"=>"Lorem ipsum", "post_status"=>"published", "comment_status"=>"closed", "comment_count"=>"0"}
save_and_continue "Save and continue"
I have managed to answer my own question, the solution was fairly easy, however maybe there is a nicer one, with more magic. Anyway using the CollectionProxy API documentation it became clear that I can assign these categories in the controller.
admin/controllers/posts.rb
Just include before the if #post.save
params[:category_active_record_relation]['id'].each do |category|
category = Category.find(category)
#post.categories << category
end
If I would create new categories than I could use the #post.categories.build(category) method.
Hope it will help others as well.

associating post and user

Here are the three files associated with the original problem, I think...please excuse my ignorance...the rails generator does a lot of work for you, so I don't understand all the connections yet.
class Post < ActiveRecord::Base
has_many :comments
belongs_to :user
default_scope { order('created_at DESC') }
end
class AddUserToPosts < ActiveRecord::Migration
def change
add_column :posts, :user_id, :integer, :name
add_index :posts, :user_id
end
end
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.text :body
t.text :name #added this
t.timestamps
end
end
end
where the error is occuring:
<%= link_to post.title, post %>
</h4>
<small>
>> submitted
<%= time_ago_in_words(post.created_at) %> ago by
<%= post.user.name %> <br/>
<!-- <%= post.comments.count %> Comments -->
</small>
Ruby is basically telling you that on line 11 (<%= post.user.name %>) the user association of your post object is nil (i.e. a non-existent value, which in Ruby is a singleton instance of class NilClass).
Thus you're trying to call the #namemethod on nil, that obviously has no such method, hence the NoMethodError.
Just add a check to make sure that user exists before printing its name <%= post.user.name unless post.user.nil? %> or make sure that there is always a user associated with your posts (e.g. through a validation), whatever fits best in your scenario.

has_many and belongs_ association rails 4

I am while leraning how to use association in rails 4 application
I have a user having many opinions and I want to add user opinion in the book show page
This is how i proceed:
my user.rb
class User < ActiveRecord::Base
has_one :panier
has_many :opinions
end
opinion.rb
class Opinion < ActiveRecord::Base
belongs_to :user
end
views/books/show.html.erb
<h2>Votre opinion nous intéresse:</h2>
<%= form_for([#user, #user.opinions.build]) do |f| %>
<p>
<%= f.label :body, 'votre opinion' %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
opinion_controller.rb
class OpinionsController < ApplicationController
def create
#user = current_user
#opinion= #user.opinion.create(opinion_params)
end
private
def opinion_params
params.require(:opinion).permit(:body)
end
end
and in books_controllers this is my show method:
def show
#user= current_user
#books= Book.all
end
my routes:
get 'books/show' => 'books#show' , as: :books_list
resources :users do
resources :opinions
end
what I got as error:
undefined method `opinions' for nil:NilClass
in this line of code:
Most probably #user.opinions in your form causing this issue. check whether current_user returning object or not.
Also in your create method there is typo(#user.opinion), it should be #user.opinions.
Use accept nested attributes for same.

How to save to Database with associations in rails protecting mass assignment

After trying for few hours I can not save to the database.
The context is this:
I have two types of users, one for that I only need very basic information [Username, email, password] and another kind of user for who I need a lot of information [age, gender, city and so on]
I did not use STI becouse of the vast quantity of Null values there would be in the table.
So I created this three modes in which a user has a profile (profiles table) or not depending of its type [1 or 2], and a field of this profile is the city this user is living in, that relates to another table in the DB, the cities table
class User < ActiveRecord::Base
has_one :profile
has_one :city, through: :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
[...a bunch of fields here]
end
class City < ActiveRecord::Base
has_many :profiles
has_many :users, through: :profiles
end
When I play with them in the rails console everything goes OK:
usr = User.new(name: "roxy", email: "roxy#example.me", password: "roxanna", password_confirmation: "roxanna", utype: 1)
cty = City.new(name: "Bucaramanga")
prf = Profile.new (rname: "Rosa Juliana Diaz del Castillo"...)
prf.city = cty
usr.profile = prf
usr.valid?
=> true
usr.save
=> true
but when I try to save in the app (View an Model)
<%= f.label :city, "En que ciudad te encuentras?"%>
<%= select_tag :city, options_from_collection_for_select(City.all, 'id', "name"),{:prompt => 'Selecciona tu ciudad'}%>
def new
#profile = Profile.new
end
def create
#profile = params[:profile]
#city= City.find_by_id(params[:city].to_i)
#profile.city = #city
end
I get this error:
undefined method `city=' for #<ActiveSupport::HashWithIndifferentAccess:0xa556fe0>
Can someone please help me?
UPDATE
As David suggested I created the Profile object in the first line of the create method, so my controller now look like this:
def create
#profile = Profile.new(params[:profile])
#city= City.find_by_id(params[:city].to_i)
#profile.city = #city
#usr = current_user
if #usr.profile.exists? #profile
#usr.errors.add(:profile, "is already assigned to this user") # or something to that effect
render :new
else
#usr.profile << #profile
redirect_to root_path
end
end
But I'm getting this error now
undefined method `exists?' for nil:NilClass
current_user returns the #current_user
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
Could you tell me please, what am I doing wrong?
I want to write this to all of you who are beginning as well as I am and are stuck in this step.
I had to create a new project and play with it to realize what I was doing wrong. I figured out that I was validating a last time field I added to the Profiles table and had
# education :string(255) not null
but I had not added it yet to the form so the error launched is:
Failed to save the new associated so_profile.
Now, you know if you got this error, go check your schema and look for NOT_NULL fields you might be missing in the form, also you can comment out all your model validations and after it's working uncomment'em to be sure.
So, my Final Models:
class User < ActiveRecord::Base
has_one :profile
has_one :city, through: :profile
attr_accessible :email, :name
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
attr_accessible :age, :fcolor, :gender
end
class City < ActiveRecord::Base
has_many :profiles
has_many :users, through: :profiles
attr_accessible :name
end
My controllers:
class ProfilesController < ApplicationController
def new
#user = User.find_by_id(params[:id])
#profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
city = City.find_by_id(params[:city])
#profile.city = city
#user = User.find_by_id(params[:userid])
#user.profile = #profile
if #user.save
flash[:success] = "Guardado"
redirect_to profile_path(id: #user.id)
end
end
def show
#user = User.find(params[:id])
end
end
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Registrado!"
redirect_to new_profile_path(id: #user.id)
else
flash[:error] = "No Registrado :("
redirect_to new
end
end
def show
#user = User.find_by_id(params[:id])
end
end
In a real app you have to use Cookies or something else to keep the session alive and therefore the user_token from where you get the user_id, but it works to play with associations.
The views:
profiles/new.html.erb
<%= #user.name %>
<%= form_for #profile, url: {action: :create, userid: #user.id } do |f| %>
<%= f.label :age, "Edad" %>
<%= f.text_field :age%> <br />
<%= label :city, "Ciudad"%>
<%= select_tag :city, options_from_collection_for_select(City.all, 'id', 'name')%>
<%= f.submit %>
<% end %>
profiles/show.html.erb
Hello <%= #user.name %><br />
Tu edad es: <%= #user.profile.age %><br />
Vives en <%= #user.profile.city.name%>
users/new.html.erb
<%= form_for #user do |f|%>
<%= f.label :name, "Nombre"%>
<%= f.text_field :name, size: 20, placeholder: "Escribe tu nombre aqui" %><br />
<%= f.label :email, "Email"%>
<%= f.text_field :email, size: 20, placeholder: "Escribe tu email aqui" %><br />
<%= f.submit "Sign me up!"%>
users/show.html.erb
Name: <%= #user.name %><br />
Email: <%= #user.email %>
And that's it!
Cheers.
Learn to read the error messages. The problem is that #profile is a hash because you didnt't actually create a new Profile object on the first line of the create method.
I think that the correct is
#so_profile.City
not
#so_profile.city
Because the class name is City

Resources