I'm implementing a classified website where I want to let user to create classified even if he is not registered. In case he is not registered I take his name, email and phone number. Its like those form on website where one can still create record without registering by only giving his email and name because asking new user to create account would turn away potential customers I am using devise and rails 4 and was wondering how can I implement this ideally.
Class User < ActiveRecord::Base
has_many :classifieds
end
class Classified < ActiveRecord::Base
belongs_to :user
end
I'm wondering if I should create a guest user as an instance of User or need to create new model to store classified poster that is not registered.
How you do this will depend mainly on how you're going to implement the user authentication
I see you've got devise as a tag - so I'll give you some ideas for it!
--
Devise
Devise has a helper called user_signed_in? - basically tells you if your current_user object is defined (and thus that your user is logged in).
In views, you can use this helper to determine how things work. A good example is in navigation:
#app/views/elements/nav.html.erb
<% if user_signed_in? %>
<%= link_to "Logout", user_session_destroy_path, method: :delete %>
<% else %>
<%= link_to "Login", new_user_session_path %>
<% end %>
In the same way, you can use the conditional nature of user_signed_in? for your form
--
Form
You'll basically need to ensure that you're able to process the form regardless of whether the user is signed in or not (I.E handle the credentials), but you could also use a conditional statement to determine which attributes to use:
<%= form_for #classified do |f| $>
<%= f.text_field :title %>
<%= f.text_field :description %>
<% if user_signed_in? %>
<%= f.fields_for :user do |user| %>
<%= user.text_field :name %>
<%= user.text_field :email %>
<%= user.text_field :phone_number %>
<% end %>
<% end %>
<% end %>
--
Controller
When you get the controller, you'll then need to consider whether the data has been submitted as form data or not. This is where user_signed_in? will again come in handy:
#app/controllers/classifieds_controller.rb
Class ClassifiedsController < ApplicationController
def new
#classified = Classified.new
#classified.build_user unless user_signed_in?
end
def create
#classified = Classified.new(classified_params)
#classified.user = current_user if user_signed_in?
end
private
def classified_params
params.require(:classified).permit(:title, :body, user_attributes(:name, :email, :phone)
end
end
What you can do is inside your create method for classifieds, you can look for a user and if he/she doesn't exist then create a dummy user with some random password and build classifieds for that dummy user. This will also keep your associations intact. Inside your create method you can do something like this:
def create
#user = User.find(params[:user_id])
if !#user
#user = User.create(attributes = {}, ...)
end
#classified = #user.classifieds.build(attributes = {}, ...)
if #classified.save
redirect_to your_path
else
render action: "new"
end
end
You can clean it more by using rails find_or_create_by method
Related
I have an edit form that is not a devise form (i have a devise edit on a different view) to edit a users details. However the form inputs only appear if the data is already there. So a user is unable to add new details to the form, as the inputs don't appear at all.
Is this happening as i'm not using a devise form view?
This is the code in my own edit file:
<%= render "devise/registrations/details", f: f, resource: #resource, addressable: #resource, default_location: nil %>
Then in the devise/registration/details i have this:
<%= f.simple_fields_for :address do |fields| %>
<%= render "address/fields", fields: fields, addressable: addressable, resource: resource %>
<% end %>
However, i think the inputs are not showing up as fields are blank in the iteration. However these fields are showing up in the actual devise/edit file, even if they are blank, just not in my new one.
When using fields_for and simple_fields_for (which is basically just a pimped up version of the former) you have to "seed" the inputs in order for them to appear.
Consider this simplified plain rails example:
class UsersController < ApplicationController
def new
#user = User.new
#user.build_address
end
# ...
end
<%= simple_form_for(#user) do |f| %>
<%= f.simple_fields_for(:address) do |af| %>
<%= af.input :street %>
<% end %>
<% end %>
If we remove the line #user.build_address there will be no nested inputs. Thats because simple_fields_for calls the method #address on #user and creates inputs for the record. If the association is one or many to many it would iterate through the association. If the method returns nil or empty there are no inputs to create - it would be like calling form_for with nil.
You can also pass a second argument to fields_for to manually specify the record object:
<%= simple_form_for(#user) do |f| %>
<%= f.simple_fields_for(:address, #user.address || #user.build_address) do |af| %>
<%= af.input :street %>
<% end %>
<% end %>
In Devise you can do this by passing a block to super or by overriding #build_resource.
class MyRegistationsController < Devise::RegistrationsController
def new
super { |resource| resource.build_address }
end
end
I have two controller in my application events and registrations. I want to send event_id of current event to registrations controller after form submission in event show template
show.html.erb
<%= form_for #registrations do |f| %>
<%= f.submit %>
<% end %>
registrations_controller
class RegistrationsController < ApplicationController
def create
#event = Event.find(params[:event_id])
end
end
but it gives me following error
cannot find event with id =
What i think that since event and registrations are not related in any way.So its giving this error.
How to solve this error
Without knowing more about the model associations and also what the #registrations object is, this is the easiest solution:
Add a hidden field to your form:
<%= f.hidden_field( :event_id, #event.id ) %>
# assumes #event exists in the show action somewhere
and in your controller:
def create
#event = Event.find(params[:registrations][:event_id])
end
If your models are associated you can do something like:
<%= form_for #event.registrations.new %>
but it's hard to say if that will work in your app based on the code provided.
I am a rookie in Rails. I am using Rails 4 and I could not find how they do this or what it is called.
I got this idea from devise where you can use devise and implement such thing in your application.html.erb file:
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
Where user is the devise model.
However when I try to search for user_signed_in or current_user variable, I cannot find it at all!
So essentially what I want to do is link this user model (which is used for devise) with another model that I created called profile. These models are linked by their ids, and if user has not created a profile, then simply ask user to create his/her profile.
To do that, I've written this to application.html.erb:
<% if user_signed_in? && (current_profile.id != current_user.id)? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
Which does not work as expected because I have not defined current_profile. The error that I am getting is:
undefined local variable or method `current_profile' for #<#<Class:0x000000044d6c60>:0x00000005d64110>
My question is, how do I create a variable named current_profile that would contain the current profile, like current_user that devise does?
The usual setup for this is to add a Profile model with a user_id:integer field.
Define an assocition on the User model
has_one :profile
Then you can access it directly using
current_user.profile
You can do the following:
class User
has_one :profile
# ...
class Profile
belongs_to :user
# ...
module ApplicationHelper # app/helpers/application_helper.rb
def current_profile
#current_profile ||= current_user.try(:profile)
#current_profile
end
# ...
# view
<% if user_signed_in? && current_profile.blank? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
So I have two models, Users that belong_to Organization (which has_many users). I'm using a partial to display all the users that belong to any one particular organization, and this is working fine if I output just the name (it correctly names all the users). However when I change the partial code to provide link_to user.name, the returned links are all links to the parent Organization rather than the individual child objects. What am I doing wrong?
Relevant code:
Organizations Controller
def show
#organization = Organization.find(params[:id])
#users_index = User.joins(:organization).where(organizations: {id: #organization.id})
end
Organization.show.html.erb
<% provide(:title, #organization.organization_name) %>
<h1><%= #organization.organization_name %></h1>
<h2>Your Organization's Users:</h2>
<%= render partial: "users_index", collection: #users_index %>
_users_index.html.erb code:
<p class="users"><%= link_to users_index.name %></p>
If you set up your relationship properly then you can use:
#users_index = #organization.users
And then you need to loop through #users_index and pass that to your partial.
#users_index.each do |user|
<%= render "users_index", :user => user %>
end
And in your partial, change to:
<p class="users"><%= link_to user.name, user %></p>
link_to
I think the core of the issue, as alluded to in the other answer, is your link_to:
<%= link_to users_index.name %>
The link_to helper method basically works like this:
<%= link_to "Your Link Text", link_path %>
I don't see how your application will be able to load the correct link path without your definition, irrespective of whether you added it to the helper or not.
I presume that your rendered link will point to "#", not the "parent object" as you alluded.
--
Fix
I'd do this:
#app/views/organization/show.html.erb
<%= render partial: "users_index", collection: #users_index, as: :user %>
#app/views/organization/_users_index.html.erb
<p class="users"><%= link_to user.name, user %></p>
This should set the correct link_to helper method for you
--
Models
Further, I would also address the associations in your models
You're currently calling users in the most inefficient way. ActiveRecord associations work to remedy this:
#app/models/user.rb
Class User < ActiveRecord::Base
belongs_to :organization
end
#app/models/organization.rb
Class Organization < ActiveRecord::Base
has_many :users
end
This will allow you to call the following:
#app/controllers/organizations_controller.rb
Class OrganizationsController < ApplicationController
def show
#organization = Organization.find params[:id]
#users_index = #organization.users
end
end
I have created a simple form to create an instance of a modle and for some reason it is not calling the create method in the controller. Here is the form code:
<% #house.mates.each do |mate| %>
<p><%= mate.name %></p>
<% end %>
<h2>Add a new mate:</h2>
<%= form_for #mate do |f| %>
<p><%= f.label "Name" %>
<%= f.text_field :name %>
<%= f.hidden_field :house_id %>
</p>
<%= f.submit "Submit", :action => :create %>
<% end %>
Here is the controller code:
class MatesController < ApplicationController
def new
#mate = Mate.new
end
def create
#mate = Mate.new(params[:mate])
#mate.save
redirect_to house_path(current_house)
end
end
There is a many to one relationship between the Mate model and the House model... I am fairly new to rails but I have made other apps with similar forms, and I have never had this problem before. I can create and save Mate objects in the console, and I am not getting any errors, so it seem that somehow the controller method is not being called. Any help is much appreciated!
In fact, if other things have no problem, your #mate object should be created. You just can't see it in house page because you have not associated #mate with house in your code.
In your form you referred :house_id, but this attribute is nil when you rendering the form.
The reason is you have not assigned it in controller.
In controller you need to initialize #mate from house object to have house_id inside it
def new
#house = something
#mate = #house.mates.new # Instead of Mate.new
end