RoR: Using a method defined in user model in a different controller - ruby-on-rails

I'm new in RoR and hoping you experts can help me on this. Apologies in advance if my question sounds weird or stupid. Let me know if you need more clarification, thanks so much in advance.
I have a boolean method called is_pollie (set default to false) in the user model which I want to change it to true once a user completed a form in a different controller called profiles_controller.rb.
Now, I have a user model with a defined method:
class User < ApplicationRecord
has_many :profiles
def self.is_pollie?
is_pollie
end
And in a different controller called profiles_controller.rb:
class ProfilesController < ApplicationController
before_action :authenticate_user!, except: [:show]
def create
#pollie = User.is_pollie?
#profile = current_user.profiles.build(profile_params)
if #profile.save
# what should I put here if I want the is_pollie? to change to true upon
a user click the save button on the form?
redirect_to basic_profile_path(#profile)
else
flash[:alert] = "Oh no, something went wrong."
render :new
end
end
In the page where the form is:
<%= form_for #profile do |f| %>
<div class="form-group">
<label>Displayed name:</label>
<%= f.text_field :display_name,class: "form-control"%>
</div>
<%= f.submit "Save", class: "btn-submit" %>
<% end %>
Hope you understand my question and are able to help. Thanks very much again.

You can try:
current_user.update(is_pollie: true)
BTW, a couple of other points...
This:
class User < ApplicationRecord
has_many :profiles
def self.is_pollie?
is_pollie
end
end
doesn't make any sense because self makes is_pollie? a class method. But, is_pollie is an instance value.
Also, you don't even need is_pollie? because you can use do current_user.is_pollie which will return true of false.
Finally, you're not using #pollie = User.is_pollie? anywhere, so why do it?

Use current_user.update_column(:is_pollie, true)
update method will trigger the call_backs, it's recommended to use update_column for updating a selected attribute.
For multiples you can use update_columns(attributes1: value, attributes2: value)

Related

Doing multiplication on my Rails App with user input

I'm just starting to learn Rails so please forgive the dumb question. In my web app, I was able to set up a working model, form, and view. A user is able to input their decimal answer and it shows on the web page perfectly. However, I want to multiple whatever the user inputs by 10. So if the user inputs 2 I want it to show 20. Any help that you guys can give me would be so amazing. I have listed below all my relevant code. Thank you again :)
Rails Controller
class Ratings1sController < ApplicationController
before_action :authenticate_user!
def create
#post = Post.find(params[:post_id])
#ratings1 = Ratings1.create(params[:ratings1].permit(:content))
#ratings1.user_id = current_user.id
#ratings1.post_id = #post.id
if #ratings1.save
redirect_to post_path(#post)
else
render 'new'
end
end
end
Rails Model
class Ratings1 < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
_Form.html
<%= simple_form_for ([#post, #post.ratings1s.build]) do |f| %>
<%= f.input_field :content %>
Assuming content is your rating that you wish to multiply simply do:
#ratings1 = Ratings1.create(params[:ratings1].permit(:content))
#ratings.content *= 10
Incidentally you are saving your Ratings1 model twice - once when creating it and then when you call save on it. It would be better to build it then save it - you may wish to add validation for presence of user for example at some point and then calling create would fail.
#ratings1 = Ratings1.build(params[:ratings1].permit(:content))

How to pass params to new view in Ruby on Rails app?

I'm trying to make simple app. I input my first name and last name to simple <%= form_for #data do |f| %> rails form and after submitting it, app should render simple text like this. My first name is <%= data.first_name %> and my last name is <%= data.last_name %>. I don't know why but my app is saying this error:
undefined local variable or method `data' for
It's probably saying it because no params are passed to view.
Here is my code.
routes.rb
resources :data, only: [:new, :create, :index]
data_controller.rb
class DataController < ApplicationController
def new
#data = Data.new
end
def index
end
def create
#data = Data.new(data_params)
if #data.valid?
redirect_to #data
else
render :new
end
end
private
def data_params
params.require(:data).permit(:first_name, :second_name)
end
end
/views/data/new.html.erb
<%= form_for #data do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :second_name %>
<%= f.text_field :second_name %>
<%= f.submit 'Continue', class: 'button' %>
<% end %>
/views/data/index.html.erb
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= data.first_name %>.</p>
<p>And my second name is: <%= data.second_name %>.</p>
/models/data.rb
class Data
include ActiveModel::Model
attr_accessor :first_name, :second_name
validates :first_name, :second_name, presence: true
end
Please help to find out why params are not passing to next page. Thanks anyways :D
Your view should look like this:
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= #data.first_name %>.</p>
<p>And my second name is: <%= #data.second_name %>.</p>
Also, I would suggest that calling a model something generic like Data is not a very Rails-y approach. Generally, domain models correspond to real-world things like User and Article, which are easy to understand and relate to. It'll get confusing quite fast if you use need to make another model and want to call it Data2 or something :)
Edit:
Since you specified that you do not wish to use the database, I would recommend passing in the object params through the redirect:
redirect_to(data_path(data: #data))
and in your controller's index method:
def index
#data = Data.new(params[:data])
end
Now your view should render properly, since you're passing the in-memory #data object attributes as params within the redirect. You then recreate this object in the index page or wherever you wish to redirect to.
To expand on Matt's answer, the reason you're getting NilClass errors is because:
You're redirecting to a data#show action when no show action has been enabled within your routes file. Since you've set your views up for the index, I'm assuming you want to redirect there when the #data object has been verified as valid:
redirect_to data_path
However I would recommend you follow Rails conventions and specify the data#show route within your routes.rb:
resources :data, only: [:index, :new, :create, :show]
and in your data_controller.rb:
def show
#data = Data.find(params[:id])
end
Another problem is that you're not actually saving the #data object upon creating it. The new method populates the attributes, and valid? runs all the validations within the specified context of your defined model and returns true if no errors are found, false otherwise. You want to do something like:
def create
#data = Data.new(data_params)
if #data.save
redirect_to data_path
else
render :new
end
end
Using save attempts to save the record to the database, and runs a validation check anyways - if validation fails the save command will return false, the record will not be saved, and the new template will be re-rendered. If it is saved properly, the controller will redirect to the index page, where you can call upon the particular data object you want and display it within your view.

Rails: How to only allow User to apply to job only once?

I am creating a job board, and I don't want to allow the users the option to apply for the same job twice. How can I limit this?
app/views/jobs/job.html.erb
<% if applied_to_this_job? %>
<div class="alert" role="alert">You have already applied to this job!</div>
<% else %>
<%= link_to 'Apply', new_job_application_path(#job) %>
<% end %>
app/helpers/jobs_helper.rb
def applied_to_this_job?
JobApplication.exists? user_id: current_user.id
end
Obviously this doesn't work because it checks if this user has applied to any job. How Can I check to see if the current user has applied to the job being viewed.
Also, how can I limit this at the controller level so that the user can't go to job_application/new and get to the form.
You would use a before_filter in the controller action.
class JobsController < ActionController::Base
before_filter :has_applied?, only: [new, create]
....
private
def has_applied?
if JobApplication.where(user_id: :current_user.id, job_id: params[:job_id]).any?
redirect_to :index, alert: "You have already applied"
end
end
end
This would allow the user to visit /jobs/new and post the application to /jobs/create unless they have applied. If they have applied, they will be redirected to the index in the sample code.
Also as another answer has noted, it would be wise to pass in the job id as well. Updated sample code above to reflect.
You need to check and see if the JobApplication object is for this #job try:
JobApplication.where( user_id: current_user.id, job_id: #job.id ).exists?
Although what you've accepted will work, I think it's somewhat of a surface-level fix.
You'll be much better using validators to determine if the user can actually create another job application. This will protect against any problems with the business logic in your "front-end" views
Here's how I'd handle it:
--
Uniq
#app/models/user.rb
class User < ActiveRecord::Base
has_one :job_application
end
#app/models/job_application.rb
class JobApplication < ActiveRecord::Base
belongs_to :user
validates :user_id, uniquness: true
end
You may also wish to give your database a uniq index for your user_id column:
> $ rails g migration AddUniqueIndex
#config/db/add_unique_index.rb
class AddUniqueIndex < ActiveRecord::Migration
def change
add_index :job_applications, [:job_id, :user_id], unique: true
end
end
This will give you a highly efficient DB-level uniqueness index - meaning that if you try and add any more applications than is permitted, it will either fail silently, or come back with an error.
Controller
The structure of the controller would allow you to be less stringent about the accessibility of the job_application functionality:
#app/views/jobs/job.html.erb
<% if current_user.has_applied?(params[:job_id]) %>
<div class="alert" role="alert">You have already applied to this job!</div>
<% else %>
<%= link_to 'Apply', new_job_application_path(#job) %>
<% end %>
#app/models/user.rb
class User < ActiveRecord::Base
has_many :job_applications
def has_applied?(job_id)
job_applications.find job_id
end
end

Display error from an associatd object Rails

I really don't know the way to display error on a view when we post datas which are associated from another model.
My needs :
I have a form displayed in app/view/libraries/show.html.erb
The comments are associated to library in my app. Means that for a library we can have one or many comments.
In model/comment.rb i put that :
validates :name, presence: true
in app/view/libraries/show.html.erb : i need to display error but don't know the way to retrieve it :
<% if #library.comment.errors.any? %>
<%= #library.comment.errors.count %>
<% end %>
CommentsController
class CommentsController < ApplicationController
def new
end
def create
#library= Library.find(params[:library_id])
#comment = #library.comments.create(params[:comment].permit(:name, :commenter))
redirect_to #library
end
end
This does not work someone can please explain to me the way it works ?? I am doing the guide rails getting start but want to add some features simple in it...
Thanks a lot guys !
If all you need is the count, you can put it in flash
def create
#library= Library.find(params[:library_id])
#comment = #library.comments.create(params[:comment].permit(:name, :commenter))
flash[:error_count] = #comment.errors.count
flash.keep[:error_count]
redirect_to #library
end
<% if flash[:error_count] > 0 %>
<%= flash[:error_count] %>
<% end %>

Undefined method 'model_name' when attempting to use Simple Form in Rails

I am attempting to get a form generated by simple-form in my modal, however I keep running into the following error upon loading the page.
undefined method 'model_name' for NilClass:Class
Here is the simple code I was using to try to generate the form
_header.html.erb (under the view_pages_controller)
<%= simple_form_for #update do |f| %>
<%= f.input :lang %>
<%= f.input :book %> #temp, just for testing simpform
<%= f.button :submit %>
<% end %>
I am pretty sure the problem lies with my controller code
updates_controller.rb
class UpdatesController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def create
#update = current_user.updates.build(params[:update])
if #update.save
flash[:success] = "Update successful"
redirect_to root_path
else
flash[:error] = "Failed to update, please try again"
redirect_to root_path
end
end
end
update.rb
class Update < ActiveRecord::Base
attr_accessible :book, :user_id, :lang, :round_id
belongs_to :user
end
Any help/tips would be greatly appreciated. I know my code sucks.
The problem is that #update is null in your view. You should clarify which action renders this view, and set value to #update. The create action only sets it based on the params, and then redirects to root.
I believe you are using some kind of RESTfull controller, and you are rendering your form on action :new. So, to solve your trouble, add
#update = current_user.updates.build(params[:update])
to your new action
Have you tried putting a debugger in above the line in your controller where you declare #update.
You could then see your current_user object and what methods are available using something like current_user.methods
Have you included resource:'updates' or resources:'updates' in routes.rb.This may solve the problem.

Resources