Rails 4 - Helper Method - use in a view - ruby-on-rails

I'm trying to figure out how to use helper methods in Rails 4.
I have two models, organisation and preferences.
The associations are:
Organisation has_one :preference
Preference belongs_to :organisation
In my preference table, I have an attribute called :prior_notice_required
In my organisation view, I'm trying to display the organisation's preferences. In my organisation view folder, I have a partial called preferences.
In my OrganisationsHelper.rb, I've tried this:
module OrganisationsHelper
def publicity_notice_required
if #organisation.preference.prior_notice_required == true
'Prior notice of publicity is required'
else
'Prior notice of publicity is not required'
end
end
In my organisation preferences partial, I then try each of these:
<%= #organisation.preference.prior_notice_required(publicity_notice_required) %>
<%= publicity_notice_required(#organisation.preference) %>
<%= publicity_notice_required(#organisation.preference.prior_notice_required) %>
I can't figure out how to get this working. Does anyone have any experience with helpers to see where I'm going wrong?

It is as simple as calling <%= publicity_notice_required %> in the view.
Rails Helpers are modules which are included across your application. This makes life easy but also has some drawbacks when it comes to Encapsulation & a good separation on concerns.

I'm not sure if this is right- but it seems to be working.
I change my view to:
<%= publicity_notice_required(#organisation.preference) %>
and my helper to:
def publicity_notice_required(organisation)
if #organisation.preference.prior_notice_required == true
'Prior notice of publicity is required'
else
'Prior notice of publicity is not required'
end
end
I'm not sure why the (organisation) needs to be in brackets or if its actually meant to include the preference as well. Hope this helps someone.

Related

Trying to create two different account types in rails

I am trying to build a simple donation app in rails. In this application, patrons would give amounts of money to clients. Both the patron and the client share large amounts of the same functionality. They are both linked to a user and have a username. However, the client is also supposed to have a content_type and a content_list property. At first glance, my guess is that I want to have both my patron and client inherit from the account class. However, the client has additional functionality, which seems to preclude any STI-based implementation (though I will be the first to admit that my understanding of STI is shaky at best). As it stands, it seems to simply make more sense to write out two separate resources, but I would like to keep my code as DRY as humanly possible. Is there a simple way for me to create the behaviors I want through inheritance, or should I simply go with overlapping resources?
Here's an idea, as both of your user-types share the same basic functionalities.
As you said, make one make one unified User or Account model. Include the database fields customer (as boolean) and patron (also as boolean).
In the signup process, the user can then select if they're a patron or customer, as they would regardless.
Then inside your view, you can then call, if you use Devise for instance (which I personally think is great)
<% if current_user.patron == true %>
<!-- all relevant UI functionality for patrons -->
<% end %>
or if the User is a customer
<% if current_user.customer == true %>
<!-- all relevant UI functionality for customers -->
<% end %>
Or if you want to loop through a list of patrons or customers:
<% #user.where(:customer == true).each do |users| %>
<% #user.first_name %> <% #user.last_name %>
<% end %>
These are just basic examples, but it would do just fine for what you're trying to achieve.
P.S You could also create one migration called "account_type" as a
string and then with the help of radio_buttons in the signup process
store the account_type as a string value.
<%= f.radio_button :account_type, "customer" %>
<%= f.radio_button :account_type, "patron" %>
I actually think that would be better. Then you would split the views up
like this:
<% if current_user.account_type => "customer" %>
Show the list that only customer should have or see.
<% end %>
<% if current_user.account_type => "patron" %>
Show the list that only patron should have or see.
<% end %>
<% #user.where(:account_type => "customer").each do |users| %>
<% #user.first_name %> <% #user.last_name %>
<% end %>
Regarding my question: Will a patron ever be a client? Will a client ever be a patron?
If the answer is "yes", you should consider creating a separate entity/model for the resource they're relating to.
With model DonationCampaign (attributes client_id, among others):
has_one :client, :class_name => 'User'
has_many :patrons, :class_name => 'DonationCampaignPatron'
DonationCampaignPatron (attributes patron_id, among others):
belongs_to :patron, :class_name => 'User'
This allows you to keep the shared functionality of User and then extend functionality to specific campaigns, without having to make other models messy, and keeps things DRY.
If a DonationCampaign could then have multiple users (as administrators, per se), to extend, a DonationCampaignRole model would be required, donation_campaign_id, user_id, role
Say you're using CanCanCan,
if can? :manage, #campaign
if can? :contribute, #campaign
:contribute would have to be added to ability.rb and could simply be #campaign.client != User
Also, STI example (the good kind, at least):
class Animal < ActiveRecord::Base
def says
raise "Implement on subclass"
end
end
class Cat < Animal
# always has a type of 'Cat'
def says
"meow"
end
end
class Dog < Animal
# always has a type of 'Dog'
def says
"woof"
end
end
And there's only one table: animals
Edit: Based on your response: From what I can learn by briefly using Patreon they have a single User model (for authentication), and then they likely have a creator_page_id in the User column. They then have a separate model CreatorPage which has all the "Client" (in your terms) info associated with it.
Personally, I would stick with a single User model for authentication and then implement the aforementioned DonationCampaign/DonationCampaignPatreon business logic. It's the most extensible with the least amount of effort (both long and shot-term).
If, for whatever reason, a Client is restricted to contributing to other Clients once they are a Client, I would forego using STI on the User model.

Restricting a model to only view their own items in the has_many

So I'm trying to think about how to route my site and I need a little help. I have a business who can .build (as in business creates) buildings (sorry for the repetition haha) in a has_many. Each property has many something else.
I would like it so even though there will be more than one building, each business should only be able to view their own buildings, so if someone tries to alter a url, it would redirect home.
I have
resources :buildings
so as it is set up, anyone could just type in
host/buildings/whatever
I would like to redirect with an error if the building ID does not belong to the current_business (devise) it will redirect to their home page. each building has a business_id
Would I have to break the RESTful for this?
Thank you!
Assuming you have user_id in builduing resource:
buildings_controller.rb
def index
#buildings = current_user.buildings
end
def show
#building = current_user.buildings.find(params[:id])
end
buildings/index.html.erb
<% #buildings.each do |building| %>
<%= building.whatever_atribute %>
<% end %>
buildings/show.html.erb
<%= #building.whatever_atribute %>
With the above code when user will go to /buildings he will see only his buildings, and if he'll go to buildings/3 he will see this building if he owns it, in other case he will see a not found error that you can customize it with a redirect or display a styled page.

activeadmin rails 4 understanding how to create custom forms

I am new to activeadmin / formtastic and I have having a bit of trouble understanding how things work. I read through the documentation on how to create a form using formtastic but I seem to be still running into issues and I am sure its me not understanding how things work.
I am creating a discussions application very similar to a blog application and the end result is that I would like to create an interface for the administrators to add comments to discussions without having to go into the users interface.
My starting point is the discussions view in the admin section presented by activeadmin. I am attempting to work on the add comment form. According to the instructions, I should be able to add a form using
form partial: 'new_admin_comment_form', locals {discussion_comment: DiscussionComment.new}
which then I should create this partial in app/views/admin/discussions folder. I have done that and have entered some arbitrary text to make sure the partial renders and it does. But once I start adding code I am not able to get the form to display.
The current code I am working with is:
<%= semantic_form_for [:admin, discussion_comment] do |f| %>
<%= f.inputs, :body %>
<%= f.actions %>
<% end %>
So a few questions I have that I wasn't able to find in the documentation:
Where do I create instance variables to be used in my form? I have been setting these in the activeadmin files and that is bothering me.
How do I pass params around? I assumed I could do this as normal yet when I try to view them using <%= debug params.inspect %>, it is empty even when I should have at least the id that was in the parent form. Even when using locals: {id: params[:id]}, id is empty in the partial.
What are the best ways to debug why my form is not appearing? Am I able to use regular ERB if worse comes to worse?
You can do this without a custom form. If you stick to the active admin DSL you can use its has_many method. Example here:
http://www.activeadmin.info/docs/5-forms.html
Your Discussion model should look like this
class Discussion < ActiveRecord::Base
has_many :discussion_comments
accepts_nested_attributes_for :discussion_comments, allow_destroy: true
end

Best Practice for Creating a Modular Form Spanning Several Different Layouts

I'm a RoR newbie (v3.2.13), and I'm building a new site/application that has a lot of landing pages, divided into 6-8 different layouts. The layouts are using similar elements in a changing order, so I'm using partials and layout inheritance to render each page appropriately.
My problem is that my forms (located at the top of each page) are also inconsistent (for example, while one page might only have a "name" and "email" fields, another will contain an additional "phone" field, a third one might also include a "password", "address" and "country" fields, etc.), and building a different partial for each page seems like a very prodigal approach, DRY wise, not to mention how ineffective it is, especially since I expect a vast amount of new pages in the future.
I've researched the forms concept thoroughly but have yet to come up with a solution that I deem good enough, probably due to me being a newbie. Unfortunately I don't have any code to present, since I waited until I make a decision regarding the optimal approach to start coding.
What I came up with so far is using jQuery and conditionals within Haml, which I understand are both naive approaches, while I read coding each field into its own partial would be considered an anti-pattern (alternatively - NOT the Rails 3 way).
Is there a best practice pertaining to such design issues? Are there any online/other resources I missed that would point me in the right direction?
Thanks!
I would solve this by building a single form with all of the elements, putting it in a partial, and including it on all of the landing pages. Then in the individual stylesheets for each landing page, hide all of the elements that you don't want to use on that particular page.
To solve potential problems with validations (e.g. you need to validate that a password was given when requested) you can create a configuration file (e.g. config/initializers/landing_forms.rb) where you specify which form fields are to be included in each, then generate the appropriate CSS from that file and also use it in your validations, i.e.:
landing_forms.rb
YourInitializer = {
foo: [:email, :password],
bar: [:email, :name, :address],
baz: [:name, :phone]
}.with_indifferent_access.freeze
_form.html.erb
<%= form_for ... do |f| %>
<%= f.hidden_field_tag :landing_page_id, value: 'foobar' %>
<% end %>
controller
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
User.validate_only requested_fields
# ...
end
protected
def requested_fields
YourConfig.fetch params[:landing_page_id]
end
end
model
class User < ActiveRecord::Base
attr_reader :required_validations
validate :email, presence: true, if: :email_required?
def email_required? # feel free to use a bit of metaprogramming to make this simpler
required_validations.include? :email
end
def validate_only(fields)
#required_validations = fields
end
end
page_forms.css.erb
/* Hide all non-button inputs by default, then show individually */
<% YourConfig.each_pair do |landing_page_id, fields| %>
<% fields.each do |field| %>
#<%= landing_page_id %> form .<% field %> { display: block }
<% end %>
<% end %>
Hopefully that's enough to get you started!
How about this sort of structure?
# Controller
#fields = [:name, :country, :phone]
# View
#fields.each do |field|
render "form/" + field.to_s
end
# form/name.html.erb
<%= text_field(:name) %>

Rails - default value in text_field but only for new_record?

On a Content model have an attribute named slug. When creating a new record, I want to use a helper to populate this field, but on an existing record I want to use the value from the database.
Currently I have:
<% if #content.new_record? %>
<%= f.text_field :slug, :value => "#{generate_slug(6)}" %>
<% else %>
<%= f.text_field :slug %>
<% end %>
But that seems a bit verbose. Is this the best way, or is there no other way? (Rails newb just trying to find the "Rails way" on issues I'm unsure of)
Edit
I should note that the helper is currently in /app/helpers/application_helper.rb Moved to be a private action in the Contents controller. David's answer worked great.
In your controller
#content.slug ||= generate_slug(6)
This will assign a value to the slug attribute if none is present
Then, in your view you can simply use
<%= f.text_field :slug %>
Options
Try after_initialize callback in your model.
Try creating a method in your model where you set defaults and call it in your new action in the controller. Also call this method if your create fails and you render new. Remember to set default only when no value exists by using the ||= operator.
Example to follow. I'm typing on phone!
I happen to use jQuery in my projects, so when I want some functionality like this, I usually use something like labelify. Then, I'd use something like <%= f.text_field :slug, :title => generate_slug(6) %>. (Hot tip, you don't need to put the #generate_slug call inside of a string if it returns something that will resolve to a string by itself, in fact it's more performant if you don't.)
If you don't want to go with jQuery approach, you might want to wrap this piece of logic in your model.
def Content < ActiveRecord::Base
def slug
self.new_record? ? self.slug_for_new_record : attributes[:slug]
end
private
def slug_for_new_record
# I don't know what you're doing in generate_slug, but it sounds model-
# related, so if so, put it here and not in a helper
end
end
If it really belongs in the view, still another option is to just make your Ruby a little bit more concise (you'll have to judge if this is more readable):
<%= f.text_field :slug, :value => (generate_slug(6) if #content.new_record?) %>
Don't forget the parens surrounding (generate_slug(6) if #content.new_record?). If you do, the if will be applied to the text_field, which is not what you want.
But there are still more ways to do it. The above line of code isn't great if your logic might change and you're pasting this code all over your rails project. When I wanted to add a 'required' class to my text fields but only if they were a new record (we had some legacy data that we didn't want to make people clean up), I created my own form builder with a required_field method that just called text_field and added a 'required' class if the item was a new record. This might seem like a work, but we have around 20 different forms, each with potentially multiple required fields, and it's a lot easier to change the business logic in one place. So if you really think this logic belongs in the view but you've got a ton of these lines of code and you don't want to have to change it in a million places, then FormBuilder is the way to go. I think this is in most cases prettier and more appropriate than a helper, but again, beauty is in the eye of the beholder. Here's my code somewhat adapted for your case:
# config/environment.rb
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder
# lib/namespaces_are_fun/form_builder.rb
module NamespacesAreFun
class FormBuilder < ActionView::Helpers::FormBuilder
def slug_field(method, options = {})
opts = options.to_options
opts.merge!(:value => generate_slug) if self.object.new_record?
text_field(method, opts)
end
end
end
# views/.../your_view.html.erb
<%= f.slug_field :slug %>
Hopefully in all of these different approaches is one that fits your project.

Resources